From 3f41fc53a1b692549c88a8602e753cfb887330ae Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Mon, 23 Jul 2018 23:06:51 +0200 Subject: [PATCH 001/143] fix 17: java 9 & 20 compatibility --- src/clj_http/lite/util.clj | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index 5906b05a..a75aa5b3 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -27,10 +27,15 @@ [unencoded] (URLEncoder/encode unencoded "UTF-8")) -(defn base64-encode +(defmacro base64-encode "Encode an array of bytes into a base64 encoded string." [unencoded] - (javax.xml.bind.DatatypeConverter/printBase64Binary unencoded)) + (if (try (import 'javax.xml.bind.DatatypeConverter) + (catch ClassNotFoundException _)) + `(javax.xml.bind.DatatypeConverter/printBase64Binary ~unencoded) + (do + (import 'java.util.Base64) + `(.encodeToString (java.util.Base64/getEncoder) ~unencoded)))) (defn to-byte-array "Returns a byte array for the InputStream provided." From 81c50911dcd38d582a8c39a5d2a5ac429dfeb2d5 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Mon, 23 Jul 2018 23:12:23 +0200 Subject: [PATCH 002/143] add deps.edn for git consumption --- deps.edn | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 deps.edn diff --git a/deps.edn b/deps.edn new file mode 100644 index 00000000..2c567bea --- /dev/null +++ b/deps.edn @@ -0,0 +1,3 @@ +{:paths ["src"] + :deps {org.clojure/clojure {:mvn/version "1.6.0"} + slingshot {:mvn/version "0.12.1"}}} From e3869255a78bc3a279f645fdf0ee051f4309e54b Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 11:01:19 +0200 Subject: [PATCH 003/143] update url of project --- CHANGELOG.md | 3 +++ changelog.org | 8 -------- project.clj | 3 +-- 3 files changed, 4 insertions(+), 10 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 changelog.org diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..389a585a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +### 0.4.0 + +- **Feature:** Java 9/10 Compatibility diff --git a/changelog.org b/changelog.org deleted file mode 100644 index 5a861edf..00000000 --- a/changelog.org +++ /dev/null @@ -1,8 +0,0 @@ -* Changelog - List of changes that have gone into each release -* Work log - Log of merges/issues/work that's gone in so I know what to put in - the changelog for the next release -** 2012-02-07 - - project start -* TODO diff --git a/project.clj b/project.clj index a75fe776..565521e3 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,6 @@ (defproject clj-http-lite "0.4.0-SNAPSHOT" :description "A Clojure HTTP library similar to clj-http, but more lightweight." - :url "https://github.com/hiredman/clj-http-lite/" - :repositories {"sona" "http://oss.sonatype.org/content/repositories/snapshots"} + :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false :dependencies [[org.clojure/clojure "1.6.0"] [slingshot "0.12.1"]] From 9dfa6b98af27c6cc63fc7a4ec8645946b45a105a Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 11:04:17 +0200 Subject: [PATCH 004/143] add note about fork status --- Readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 10c9a78d..af1f3399 100644 --- a/Readme.md +++ b/Readme.md @@ -3,10 +3,11 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. +> This is a somewhat maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. + ## Installation -`clj-http-lite` is available as a Maven artifact -from [Clojars](http://clojars.org/clj-http-lite): +`clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): ```clojure [clj-http-lite "0.3.0"] From bdc755f34e4a97494fd35b45942104ebd15c7510 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 15:36:03 +0200 Subject: [PATCH 005/143] change project coordinate --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 565521e3..44377bf4 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject clj-http-lite "0.4.0-SNAPSHOT" +(defproject org.martinklepsch/clj-http-lite "0.4.0-SNAPSHOT" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false From 53fdc114b7d55006d7976cdc3093862e7945ad45 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 15:37:36 +0200 Subject: [PATCH 006/143] add license to project.clj --- project.clj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project.clj b/project.clj index 44377bf4..5bd8de3a 100644 --- a/project.clj +++ b/project.clj @@ -2,6 +2,8 @@ :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false + :license {:name "MIT" + :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.6.0"] [slingshot "0.12.1"]] :profiles {:dev {:dependencies [[ring/ring-jetty-adapter "1.3.2"] From 525216af56f9a5738cac4da4972eef00c3a9be3c Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 15:41:59 +0200 Subject: [PATCH 007/143] update dependencies --- project.clj | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/project.clj b/project.clj index 5bd8de3a..0ac4e011 100644 --- a/project.clj +++ b/project.clj @@ -4,15 +4,16 @@ :warn-on-reflection false :license {:name "MIT" :url "http://www.opensource.org/licenses/mit-license.php"} - :dependencies [[org.clojure/clojure "1.6.0"] - [slingshot "0.12.1"]] + :dependencies [[org.clojure/clojure "1.8.0"] + [slingshot "0.12.2"]] :profiles {:dev {:dependencies [[ring/ring-jetty-adapter "1.3.2"] [ring/ring-devel "1.3.2"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} - :1.7 {:dependencies [[org.clojure/clojure "1.7.0-alpha5"]]}} + :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} + :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}} :test-selectors {:default #(not (:integration %)) :integration :integration :all (constantly true)} - :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev:dev,1.7"]} + :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev,1.6:dev,1.7:dev,1.8"]} :checksum-deps true) From ce38cabbd29b3e7b4b0fe70cb1ee58820e13256a Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 15:49:10 +0200 Subject: [PATCH 008/143] update readme; document known issues --- Readme.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index af1f3399..1000038f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,10 +1,11 @@ # `clj-http-lite` -A Clojure HTTP library similar to -[clj-http](http://github.com/dakrone/clj-http), but more lightweight. +A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. > This is a somewhat maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. +[Installation](#installation) | [Usage](#usage) | [Known Issues](#known-issues) | [Design](#design) | [Development](#development) + ## Installation `clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): @@ -192,6 +193,15 @@ If you need to fake clj-http responses (for things like testing and such), check out the [clj-http-fake](https://github.com/myfreeweb/clj-http-fake) library. +## Known Issues + +- Nested form params [aren't serialized correctly](https://github.com/hiredman/clj-http-lite/issues/15). There's an easy workaround however: + + ```clojure + :form-params {"toplevel" {"nested" some-data}} ; doesn't work + :form-params {"toplevel[nested]" some-data} ; works + ``` + ## Design The design of `clj-http` is inspired by the From 05e83b9516a7ddfd8f1e6e27e11f93b44134fba7 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 15:55:22 +0200 Subject: [PATCH 009/143] add CI config --- .circleci/config.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..e6a749ba --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,18 @@ +version: 2 +jobs: + build: + working_directory: ~/clj-http-lite + docker: + - image: circleci/clojure:lein-2.7.1 + environment: + JVM_OPTS: -Xmx3200m + steps: + - checkout + - restore_cache: + key: clj-http-lite-{{ checksum "project.clj" }} + - run: lein deps + - save_cache: + paths: + - ~/.m2 + key: clj-http-lote-{{ checksum "project.clj" }} + - run: lein all do clean, test :all From b951b6771e2e2c31e76c76b39c8f47af54253051 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:01:57 +0200 Subject: [PATCH 010/143] delete cookie namespace --- src/clj_http/lite/cookies.clj | 117 ---------------------------------- 1 file changed, 117 deletions(-) delete mode 100644 src/clj_http/lite/cookies.clj diff --git a/src/clj_http/lite/cookies.clj b/src/clj_http/lite/cookies.clj deleted file mode 100644 index f2f709bf..00000000 --- a/src/clj_http/lite/cookies.clj +++ /dev/null @@ -1,117 +0,0 @@ -(ns clj-http.lite.cookies - (:use [clj-http.lite.util :only [url-decode url-encode]] - [clojure.string :only [blank? join lower-case]]) - (:import (org.apache.http.client.params ClientPNames CookiePolicy) - (org.apache.http.cookie ClientCookie CookieOrigin) - (org.apache.http.params BasicHttpParams) - (org.apache.http.impl.cookie BasicClientCookie2) - (org.apache.http.impl.cookie BrowserCompatSpecFactory) - (org.apache.http.message BasicHeader))) - -(defn- cookie-spec ^org.apache.http.cookie.CookieSpec [] - (.newInstance - (BrowserCompatSpecFactory.) - (doto (BasicHttpParams.) - (.setParameter ClientPNames/COOKIE_POLICY - CookiePolicy/BROWSER_COMPATIBILITY)))) - -(defn- compact-map - "Removes all map entries where value is nil." - [m] - (reduce #(if (get m %2) (assoc %1 %2 (get m %2)) %1) - (sorted-map) (sort (keys m)))) - -(defn- to-cookie - "Converts a ClientCookie object into a tuple where the first item is - the name of the cookie and the second item the content of the - cookie." - [#^ClientCookie cookie] - [(.getName cookie) - (compact-map - {:comment (.getComment cookie) - :comment-url (.getCommentURL cookie) - :discard (not (.isPersistent cookie)) - :domain (.getDomain cookie) - :expires (if (.getExpiryDate cookie) (.getExpiryDate cookie)) - :path (.getPath cookie) - :ports (if (.getPorts cookie) (seq (.getPorts cookie))) - :secure (.isSecure cookie) - :value (try - (url-decode (.getValue cookie)) - (catch Exception _ (.getValue cookie))) - :version (.getVersion cookie)})]) - -(defn- to-basic-client-cookie - "Converts a cookie seq into a BasicClientCookie2." - [[cookie-name cookie-content]] - (doto (BasicClientCookie2. (name cookie-name) - (url-encode (name (:value cookie-content)))) - (.setComment (:comment cookie-content)) - (.setCommentURL (:comment-url cookie-content)) - (.setDiscard (or (:discard cookie-content) true)) - (.setDomain (:domain cookie-content)) - (.setExpiryDate (:expires cookie-content)) - (.setPath (:path cookie-content)) - (.setPorts (int-array (:ports cookie-content))) - (.setSecure (or (:secure cookie-content) false)) - (.setVersion (or (:version cookie-content) 0)))) - -(defn decode-cookie - "Decode the Set-Cookie string into a cookie seq." - [set-cookie-str] - (if-not (blank? set-cookie-str) - ;; I just want to parse a cookie without providing origin. How? - (let [domain (lower-case (str (gensym))) - origin (CookieOrigin. domain 80 "/" false) - [cookie-name cookie-content] (-> (cookie-spec) - (.parse (BasicHeader. - "set-cookie" - set-cookie-str) - origin) - first - to-cookie)] - [cookie-name - (if (= domain (:domain cookie-content)) - (dissoc cookie-content :domain) cookie-content)]))) - -(defn decode-cookies - "Converts a cookie string or seq of strings into a cookie map." - [cookies] - (reduce #(assoc %1 (first %2) (second %2)) {} - (map decode-cookie (if (sequential? cookies) cookies [cookies])))) - -(defn decode-cookie-header - "Decode the Set-Cookie header into the cookies key." - [response] - (if-let [cookies (get (:headers response) "set-cookie")] - (assoc response - :cookies (decode-cookies cookies) - :headers (dissoc (:headers response) "set-cookie")) - response)) - -(defn encode-cookie - "Encode the cookie into a string used by the Cookie header." - [cookie] - (when-let [header (-> (cookie-spec) - (.formatCookies [(to-basic-client-cookie cookie)]) - first)] - (.getValue ^org.apache.http.Header header))) - -(defn encode-cookies - "Encode the cookie map into a string." - [cookie-map] (join ";" (map encode-cookie (seq cookie-map)))) - -(defn encode-cookie-header - "Encode the :cookies key of the request into a Cookie header." - [request] - (if (:cookies request) - (-> request - (assoc-in [:headers "Cookie"] (encode-cookies (:cookies request))) - (dissoc :cookies)) - request)) - -(defn wrap-cookies - [client] - (fn [request] - (let [response (client (encode-cookie-header request))] - (decode-cookie-header response)))) From f0c1a333ee8f48aa22c988fe64041cf68c07c6eb Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:05:20 +0200 Subject: [PATCH 011/143] add 1.9 profile --- project.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/project.clj b/project.clj index 0ac4e011..e0758d05 100644 --- a/project.clj +++ b/project.clj @@ -11,9 +11,10 @@ :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} - :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}} + :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} + :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}} :test-selectors {:default #(not (:integration %)) :integration :integration :all (constantly true)} - :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev,1.6:dev,1.7:dev,1.8"]} + :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev,1.6:dev,1.7:dev,1.8:dev,1.9"]} :checksum-deps true) From 954a26e9b4a628d459f36f387cca48ebd000f03a Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:07:30 +0200 Subject: [PATCH 012/143] release 0.4.0 --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index e0758d05..bf74d9cb 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.0-SNAPSHOT" +(defproject org.martinklepsch/clj-http-lite "0.4.0" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false From 3d083ceddf8a7e6b50150b2233b74fa79cf55019 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:11:05 +0200 Subject: [PATCH 013/143] add badges to readme --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 1000038f..f2c91d89 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -# `clj-http-lite` +# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.martinklepsch/clj-http-lite)](https://cljdoc.xyz/d/org.martinklepsch/clj-http-lite/CURRENT) [![CircleCI](https://circleci.com/gh/martinklepsch/clj-http-lite.svg?style=svg)](https://circleci.com/gh/martinklepsch/clj-http-lite) A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. From 9f38378d7545651af0febfa2fc8bfa87953cf6b4 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:11:43 +0200 Subject: [PATCH 014/143] update coordinate info in readme --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index f2c91d89..b4fa7837 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): ```clojure -[clj-http-lite "0.3.0"] +[org.martinklepsch/clj-http-lite "0.4.0"] ``` ## Differences from clj-http From c6c3d61f819f4bcac0b9ec15aa63da1245e50fcb Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 17 Oct 2018 16:13:05 +0200 Subject: [PATCH 015/143] 0.4.1 --- Readme.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index b4fa7837..e61e0617 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): ```clojure -[org.martinklepsch/clj-http-lite "0.4.0"] +[org.martinklepsch/clj-http-lite "0.4.1"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index bf74d9cb..d442786e 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.0" +(defproject org.martinklepsch/clj-http-lite "0.4.1" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false From 05d0454e369d7c5e4c4faeb48ce5a20a5e2daf29 Mon Sep 17 00:00:00 2001 From: Ivar Refsdal Date: Wed, 4 Dec 2019 10:54:42 +0100 Subject: [PATCH 016/143] Add type hints for GraalVM (#2) --- src/clj_http/lite/util.clj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index a75aa5b3..c05eedc8 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -19,12 +19,13 @@ (defn url-decode "Returns the form-url-decoded version of the given string, using either a specified encoding or UTF-8 by default." - [encoded & [encoding]] - (URLDecoder/decode encoded (or encoding "UTF-8"))) + [^String encoded & [encoding]] + (let [^String encoding (or encoding "UTF-8")] + (URLDecoder/decode encoded encoding))) (defn url-encode "Returns an UTF-8 URL encoded version of the given string." - [unencoded] + [^String unencoded] (URLEncoder/encode unencoded "UTF-8")) (defmacro base64-encode From dacd3e3b5a4009f571ed617fe0f50238f506eb48 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 4 Dec 2019 10:58:49 +0100 Subject: [PATCH 017/143] 0.4.2 --- CHANGELOG.md | 4 ++++ Readme.md | 2 +- project.clj | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 389a585a..17c656c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 0.4.2 + +- type hints for GraalVM ([#2](https://github.com/martinklepsch/clj-http-lite/pull/2)) + ### 0.4.0 - **Feature:** Java 9/10 Compatibility diff --git a/Readme.md b/Readme.md index e61e0617..cfe29882 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): ```clojure -[org.martinklepsch/clj-http-lite "0.4.1"] +[org.martinklepsch/clj-http-lite "0.4.2"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index d442786e..231c46d3 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.1" +(defproject org.martinklepsch/clj-http-lite "0.4.2" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false From e5cb83fabfd7c84db07b771f334e090601ad8388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imre=20K=C3=B3sz=C3=B3?= Date: Thu, 21 Nov 2019 17:12:42 +0100 Subject: [PATCH 018/143] Add parsing of link headers Imported from https://github.com/dakrone/clj-http/tree/217393258e7863514debece4eb7b23a7a3fa8bd9 --- CHANGELOG.md | 6 ++- src/clj_http/lite/client.clj | 2 + src/clj_http/lite/links.clj | 67 +++++++++++++++++++++++++++++++ test/clj_http/test/links_test.clj | 39 ++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/clj_http/lite/links.clj create mode 100644 test/clj_http/test/links_test.clj diff --git a/CHANGELOG.md b/CHANGELOG.md index 17c656c4..75ea5210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ +### Unreleased + +- **Feature:** Parse link headers from response and put them under `:links` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/1)) + ### 0.4.2 -- type hints for GraalVM ([#2](https://github.com/martinklepsch/clj-http-lite/pull/2)) +- Add type hints for GraalVM ([#2](https://github.com/martinklepsch/clj-http-lite/pull/2)) ### 0.4.0 diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index 60dc7e86..2878e4c6 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -4,6 +4,7 @@ (:require [clojure.string :as str] [clojure.java.io :as io] [clj-http.lite.core :as core] + [clj-http.lite.links :refer [wrap-links]] [clj-http.lite.util :as util]) (:import (java.io InputStream File) (java.net URL UnknownHostException)) @@ -240,6 +241,7 @@ wrap-content-type wrap-form-params wrap-method + wrap-links wrap-unknown-host)) (def #^{:doc diff --git a/src/clj_http/lite/links.clj b/src/clj_http/lite/links.clj new file mode 100644 index 00000000..87f9a807 --- /dev/null +++ b/src/clj_http/lite/links.clj @@ -0,0 +1,67 @@ +(ns clj-http.lite.links + "Namespace dealing with HTTP link headers + + Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/src/clj_http/links.clj") + +(def ^:private quoted-string + #"\"((?:[^\"]|\\\")*)\"") + +(def ^:private token + #"([^,\";]*)") + +(def ^:private link-param + (re-pattern (str "(\\w+)=(?:" quoted-string "|" token ")"))) + +(def ^:private uri-reference + #"<([^>]*)>") + +(def ^:private link-value + (re-pattern (str uri-reference "((?:\\s*;\\s*" link-param ")*)"))) + +(def ^:private link-header + (re-pattern (str "(?:\\s*(" link-value ")\\s*,?\\s*)"))) + +(defn read-link-params [params] + (into {} + (for [[_ name quot tok] (re-seq link-param params)] + [(keyword name) (or quot tok)]))) + +(defn read-link-value [value] + (let [[_ uri params] (re-matches link-value value) + param-map (read-link-params params)] + [(keyword (:rel param-map)) + (-> param-map + (assoc :href uri) + (dissoc :rel))])) + +(defn read-link-headers [header] + (->> (re-seq link-header header) + (map second) + (map read-link-value) + (into {}))) + +(defn- links-response + [response] + (if-let [link-headers (get-in response [:headers "link"])] + (let [link-headers (if (coll? link-headers) + link-headers + [link-headers])] + (assoc response + :links + (into {} (map read-link-headers link-headers)))) + response)) + +(defn wrap-links + "Add a :links key to the response map that contains parsed Link headers. The + links will be represented as a map, with the 'rel' value being the key. The + URI is placed under the 'href' key, to mimic the HTML link element. + + e.g. Link: ; rel=next; title=\"Page 2\" + => {:links {:next {:href \"http://example.com/page2.html\" + :title \"Page 2\"}}}" + [client] + (fn + ([request] + (links-response (client request))) + ([request respond raise] + (client request #(respond (links-response %)) raise)))) diff --git a/test/clj_http/test/links_test.clj b/test/clj_http/test/links_test.clj new file mode 100644 index 00000000..1813e9ee --- /dev/null +++ b/test/clj_http/test/links_test.clj @@ -0,0 +1,39 @@ +(ns clj-http.test.links-test + "Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/test/clj_http/test/links_test.clj" + (:require [clj-http.lite.links :refer :all] + [clojure.test :refer :all])) + +(defn- link-handler [link-header] + (wrap-links (constantly {:headers {"link" link-header}}))) + +(deftest test-wrap-links + (testing "absolute link" + (let [handler (link-handler "; rel=next")] + (is (= (:links (handler {})) + {:next {:href "http://example.com/page2.html"}})))) + (testing "relative link" + (let [handler (link-handler ";rel=next")] + (is (= (:links (handler {})) + {:next {:href "/page2.html"}})))) + (testing "extra params" + (let [handler (link-handler "; rel=next; title=\"Page 2\"")] + (is (= (:links (handler {})) + {:next {:href "/page2.html", :title "Page 2"}})))) + (testing "multiple headers" + (let [handler (link-handler ";rel=prev, ;rel=next,;rel=home")] + (is (= (:links (handler {})) + {:prev {:href "/p1"} + :next {:href "/p3"} + :home {:href "/"}})))) + (testing "no :links key if no link headers" + (let [handler (wrap-links (constantly {:headers {}})) + response (handler {})] + (is (not (contains? response :links)))))) + +(deftest t-multiple-link-headers + (let [handler (link-handler ["; rel=shorturl" + "; rel=icon"]) + resp (handler {})] + (is (= (:links resp) + {:shorturl {:href "http://example.com/Zl_A"} + :icon {:href "http://example.com/foo.png"}})))) From 3ee08ac33ec8682b792230fc806b7f813c72235e Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 4 Dec 2019 11:12:55 +0100 Subject: [PATCH 019/143] 0.4.3 --- CHANGELOG.md | 2 +- Readme.md | 4 ++-- project.clj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ea5210..22845686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### Unreleased +### 0.4.3 - **Feature:** Parse link headers from response and put them under `:links` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/1)) diff --git a/Readme.md b/Readme.md index cfe29882..bffdfab5 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.martinklepsch/clj-http-lite)](https://cljdoc.xyz/d/org.martinklepsch/clj-http-lite/CURRENT) [![CircleCI](https://circleci.com/gh/martinklepsch/clj-http-lite.svg?style=svg)](https://circleci.com/gh/martinklepsch/clj-http-lite) -A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. +A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. > This is a somewhat maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): ```clojure -[org.martinklepsch/clj-http-lite "0.4.2"] +[org.martinklepsch/clj-http-lite "0.4.3"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 231c46d3..7630cfa2 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.2" +(defproject org.martinklepsch/clj-http-lite "0.4.3" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :warn-on-reflection false From a884410c93e93c7acd8a0cb465c4b28268bf731b Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Wed, 4 Dec 2019 10:40:27 +0000 Subject: [PATCH 020/143] Handle CI via GH Actions (#3) --- .circleci/config.yml | 18 ------------------ .github/workflows/ci.yml | 19 +++++++++++++++++++ Readme.md | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index e6a749ba..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: 2 -jobs: - build: - working_directory: ~/clj-http-lite - docker: - - image: circleci/clojure:lein-2.7.1 - environment: - JVM_OPTS: -Xmx3200m - steps: - - checkout - - restore_cache: - key: clj-http-lite-{{ checksum "project.clj" }} - - run: lein deps - - save_cache: - paths: - - ~/.m2 - key: clj-http-lote-{{ checksum "project.clj" }} - - run: lein all do clean, test :all diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..b3004662 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: Tests +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Prepare java + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Setup Clojure + uses: DeLaGuardo/setup-clojure@2.0 + with: + lein: 2.9.1 + - name: Checkout + uses: actions/checkout@v2-beta + - name: Run tests + run: lein test :all diff --git a/Readme.md b/Readme.md index bffdfab5..425f2350 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.martinklepsch/clj-http-lite)](https://cljdoc.xyz/d/org.martinklepsch/clj-http-lite/CURRENT) [![CircleCI](https://circleci.com/gh/martinklepsch/clj-http-lite.svg?style=svg)](https://circleci.com/gh/martinklepsch/clj-http-lite) +# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.martinklepsch/clj-http-lite)](https://cljdoc.xyz/d/org.martinklepsch/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. From 6bd9ab365b1adf7b50a2303259a9ae411fab41b0 Mon Sep 17 00:00:00 2001 From: Avichal Pandey Date: Tue, 7 Jan 2020 13:51:46 +0100 Subject: [PATCH 021/143] Update link to Clojars (#4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The link to Clojars was pointing to `clj-http-lite/clj-http-lite` on Maven. Updated it to `org.martinklepsch/clj-http-lite` 🙂 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 425f2350..2d523f15 100644 --- a/Readme.md +++ b/Readme.md @@ -8,7 +8,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) ## Installation -`clj-http-lite` is available as a Maven artifact from [Clojars](http://clojars.org/clj-http-lite): +`clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure [org.martinklepsch/clj-http-lite "0.4.3"] From 7c46264c2e8626667a8063b95b21fb584852ac45 Mon Sep 17 00:00:00 2001 From: Arnaud Bos Date: Tue, 7 Apr 2020 15:31:25 +0200 Subject: [PATCH 022/143] Add a note to enable HTTPS support at compile time (#6) --- Readme.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Readme.md b/Readme.md index 2d523f15..53ac177f 100644 --- a/Readme.md +++ b/Readme.md @@ -202,6 +202,16 @@ such), check out the :form-params {"toplevel[nested]" some-data} ; works ``` +- If you issue HTTPS connections, [Native Image](https://www.graalvm.org/docs/reference-manual/native-image/) compilation requires an additional parameter in order to enable its support in the generated image. + + If you get the following kind of error: + + Exception in thread "main" java.net.MalformedURLException: Accessing an URL protocol that was not enabled. + The URL protocol https is supported but not enabled by default. It must be enabled by adding the + -H:EnableURLProtocols=https option to the native-image command. + + Then add either `-H:EnableURLProtocols=https` or `--enable-https` option to your compilation step. + ## Design The design of `clj-http` is inspired by the From 8de4728520d75e0054b1774b18e7e7c04be85569 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 28 May 2020 22:58:35 +0200 Subject: [PATCH 023/143] [#8] fix reflection warning --- project.clj | 2 +- src/clj_http/lite/core.clj | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/project.clj b/project.clj index 7630cfa2..7ba28c9e 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,7 @@ (defproject org.martinklepsch/clj-http-lite "0.4.3" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" - :warn-on-reflection false + :global-vars {*warn-on-reflection* true} :license {:name "MIT" :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.8.0"] diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 246d1d2f..11eda6a9 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -53,7 +53,7 @@ (when server-port (str ":" server-port)) uri (when query-string (str "?" query-string))) - conn (.openConnection ^URL (URL. http-url))] + ^HttpURLConnection conn (.openConnection ^URL (URL. http-url))] (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" @@ -63,8 +63,8 @@ (doseq [[h v] headers] (.setRequestProperty conn h v)) (when (false? follow-redirects) - (.setInstanceFollowRedirects ^HttpURLConnection conn false)) - (.setRequestMethod ^HttpURLConnection conn (.toUpperCase (name request-method))) + (.setInstanceFollowRedirects conn false)) + (.setRequestMethod conn (.toUpperCase (name request-method))) (when body (.setDoOutput conn true)) (when socket-timeout @@ -78,7 +78,7 @@ (with-open [out (.getOutputStream conn)] (io/copy body out))) (merge {:headers (parse-headers conn) - :status (.getResponseCode ^HttpURLConnection conn) + :status (.getResponseCode conn) :body (when-not (= request-method :head) (coerce-body-entity req conn))} (when save-request? From 7c5f87c6bd69904eb25ec5c233feb1c05f7aab2e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 29 May 2020 15:55:04 +0200 Subject: [PATCH 024/143] Move warn-on-reflection setting to namespaces --- project.clj | 1 - src/clj_http/lite/client.clj | 2 ++ src/clj_http/lite/core.clj | 2 ++ src/clj_http/lite/links.clj | 2 ++ src/clj_http/lite/util.clj | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 7ba28c9e..d1173132 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,6 @@ (defproject org.martinklepsch/clj-http-lite "0.4.3" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" - :global-vars {*warn-on-reflection* true} :license {:name "MIT" :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.8.0"] diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index 2878e4c6..f0aeda8d 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -10,6 +10,8 @@ (java.net URL UnknownHostException)) (:refer-clojure :exclude (get update))) +(set! *warn-on-reflection* true) + (defn update [m k f & args] (assoc m k (apply f (m k) args))) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 11eda6a9..5bdc6b05 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -4,6 +4,8 @@ (:import (java.io ByteArrayOutputStream InputStream IOException) (java.net URI URL HttpURLConnection))) +(set! *warn-on-reflection* true) + (defn parse-headers "Takes a URLConnection and returns a map of names to values. diff --git a/src/clj_http/lite/links.clj b/src/clj_http/lite/links.clj index 87f9a807..3456439d 100644 --- a/src/clj_http/lite/links.clj +++ b/src/clj_http/lite/links.clj @@ -3,6 +3,8 @@ Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/src/clj_http/links.clj") +(set! *warn-on-reflection* true) + (def ^:private quoted-string #"\"((?:[^\"]|\\\")*)\"") diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index c05eedc8..32b65232 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -6,6 +6,8 @@ (java.util.zip InflaterInputStream DeflaterInputStream GZIPInputStream GZIPOutputStream))) +(set! *warn-on-reflection* true) + (defn utf8-bytes "Returns the UTF-8 bytes corresponding to the given string." [#^String s] From 50410604985fd804ce7df999e1f87469bfba6ec3 Mon Sep 17 00:00:00 2001 From: Gary Date: Thu, 20 Aug 2020 11:10:25 -0400 Subject: [PATCH 025/143] Update to support insecure SSL validation Signed-off-by: Gary --- src/clj_http/lite/core.clj | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 5bdc6b05..9d3147fb 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -2,7 +2,9 @@ "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) (:import (java.io ByteArrayOutputStream InputStream IOException) - (java.net URI URL HttpURLConnection))) + (java.net URI URL HttpURLConnection) + (javax.net.ssl SSLContext X509TrustManager TrustManager HttpsURLConnection HostnameVerifier SSLSession) + (java.security SecureRandom))) (set! *warn-on-reflection* true) @@ -41,6 +43,19 @@ (.flush baos) (.toByteArray baos))))) +(defn my-host-verifier [] + (proxy [HostnameVerifier] [] + (verify [^String hostname ^SSLSession session] true))) + +(defn trust-invalid-manager [] + "This allows the ssl socket to connect with invalid/self-signed SSL certs." + (reify X509TrustManager + (getAcceptedIssuers [this] nil) + (checkClientTrusted [this certs authType]) + (checkServerTrusted [this certs authType]) + ) + ) + (defn request "Executes the HTTP request corresponding to the given Ring request map and returns the Ring response map corresponding to the resulting HTTP response. @@ -55,7 +70,11 @@ (when server-port (str ":" server-port)) uri (when query-string (str "?" query-string))) - ^HttpURLConnection conn (.openConnection ^URL (URL. http-url))] + ^HttpURLConnection conn (.openConnection ^URL (URL. http-url)) + ssl-context (doto (SSLContext/getInstance "SSL") + (.init nil (into-array TrustManager [(trust-invalid-manager)]) (new SecureRandom)))] + (when insecure? (HttpsURLConnection/setDefaultSSLSocketFactory (.getSocketFactory ssl-context)) + (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))) (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" From f549627b7b9bdb8739e3b5592e72ffe091b7c51f Mon Sep 17 00:00:00 2001 From: Gary Date: Thu, 20 Aug 2020 20:24:03 -0400 Subject: [PATCH 026/143] Update to support Self-signed Cert and auth Signed-off-by: Gary --- src/clj_http/lite/core.clj | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 9d3147fb..68fd3ce9 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -70,11 +70,14 @@ (when server-port (str ":" server-port)) uri (when query-string (str "?" query-string))) - ^HttpURLConnection conn (.openConnection ^URL (URL. http-url)) - ssl-context (doto (SSLContext/getInstance "SSL") - (.init nil (into-array TrustManager [(trust-invalid-manager)]) (new SecureRandom)))] - (when insecure? (HttpsURLConnection/setDefaultSSLSocketFactory (.getSocketFactory ssl-context)) - (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))) + _ (when insecure? + (do (HttpsURLConnection/setDefaultSSLSocketFactory + (.getSocketFactory + (doto (SSLContext/getInstance "TLS") + (.init nil (into-array TrustManager [(trust-invalid-manager)]) + (new SecureRandom))))) + (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier)))) + ^HttpURLConnection conn (.openConnection ^URL (URL. http-url))] (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" @@ -99,9 +102,9 @@ (with-open [out (.getOutputStream conn)] (io/copy body out))) (merge {:headers (parse-headers conn) - :status (.getResponseCode conn) - :body (when-not (= request-method :head) - (coerce-body-entity req conn))} + :status (.getResponseCode conn) + :body (when-not (= request-method :head) + (coerce-body-entity req conn))} (when save-request? {:request (assoc (dissoc req :save-request?) :http-url http-url)})))) From 714ecab9fc0df7fc1747ad6ed7433a6314078f41 Mon Sep 17 00:00:00 2001 From: Gary Berger <58652+gaberger@users.noreply.github.com> Date: Mon, 24 Aug 2020 12:12:02 -0400 Subject: [PATCH 027/143] Update src/clj_http/lite/core.clj Co-authored-by: Martin Klepsch --- src/clj_http/lite/core.clj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 68fd3ce9..f399f597 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -52,9 +52,7 @@ (reify X509TrustManager (getAcceptedIssuers [this] nil) (checkClientTrusted [this certs authType]) - (checkServerTrusted [this certs authType]) - ) - ) + (checkServerTrusted [this certs authType]))) (defn request "Executes the HTTP request corresponding to the given Ring request map and From 40634dc62d2e9d0b15c8f8ca793032b5a53b8426 Mon Sep 17 00:00:00 2001 From: Gary Date: Mon, 24 Aug 2020 12:35:34 -0400 Subject: [PATCH 028/143] Update for PR Signed-off-by: Gary --- CHANGELOG.md | 3 +++ Readme.md | 1 - deps.edn | 3 +-- src/clj_http/lite/core.clj | 10 ++++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22845686..ed54f0dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### unreleased +Update to support self-signed certificates via insecure? option + ### 0.4.3 - **Feature:** Parse link headers from response and put them under `:links` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/1)) diff --git a/Readme.md b/Readme.md index 53ac177f..dbe0a6d3 100644 --- a/Readme.md +++ b/Readme.md @@ -22,7 +22,6 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) - No proxy-ing DELETEs with body - No multipart form uploads - No persistent connection support -- No support for insecure HTTPS connection (yet) - namespace rename clj-http.* -> clj-http.lite.* ## Usage diff --git a/deps.edn b/deps.edn index 2c567bea..934123d7 100644 --- a/deps.edn +++ b/deps.edn @@ -1,3 +1,2 @@ {:paths ["src"] - :deps {org.clojure/clojure {:mvn/version "1.6.0"} - slingshot {:mvn/version "0.12.1"}}} + :deps {org.clojure/clojure {:mvn/version "1.10.0"}}} diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 68fd3ce9..f0c2f4f4 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -2,8 +2,8 @@ "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) (:import (java.io ByteArrayOutputStream InputStream IOException) - (java.net URI URL HttpURLConnection) - (javax.net.ssl SSLContext X509TrustManager TrustManager HttpsURLConnection HostnameVerifier SSLSession) + (java.net URL HttpURLConnection) + (javax.net.ssl HttpsURLConnection SSLContext TrustManager X509TrustManager HostnameVerifier SSLSession) (java.security SecureRandom))) (set! *warn-on-reflection* true) @@ -52,9 +52,7 @@ (reify X509TrustManager (getAcceptedIssuers [this] nil) (checkClientTrusted [this certs authType]) - (checkServerTrusted [this certs authType]) - ) - ) + (checkServerTrusted [this certs authType]))) (defn request "Executes the HTTP request corresponding to the given Ring request map and @@ -73,7 +71,7 @@ _ (when insecure? (do (HttpsURLConnection/setDefaultSSLSocketFactory (.getSocketFactory - (doto (SSLContext/getInstance "TLS") + (doto (SSLContext/getInstance "SSL") (.init nil (into-array TrustManager [(trust-invalid-manager)]) (new SecureRandom))))) (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier)))) From 49849a6d79d94a7edd8d57f2d5ee19186146d258 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Mon, 31 Aug 2020 13:11:25 +0200 Subject: [PATCH 029/143] undo whitespace changes --- src/clj_http/lite/core.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index f0c2f4f4..a002df1f 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -100,9 +100,9 @@ (with-open [out (.getOutputStream conn)] (io/copy body out))) (merge {:headers (parse-headers conn) - :status (.getResponseCode conn) - :body (when-not (= request-method :head) - (coerce-body-entity req conn))} + :status (.getResponseCode conn) + :body (when-not (= request-method :head) + (coerce-body-entity req conn))} (when save-request? {:request (assoc (dissoc req :save-request?) :http-url http-url)})))) From 75f33299c617dd45b24e57b843e8e5125858a527 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 8 Jun 2021 23:54:06 +0200 Subject: [PATCH 030/143] Remove unused `ring/ring-devel` --- project.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/project.clj b/project.clj index d1173132..987f03d0 100644 --- a/project.clj +++ b/project.clj @@ -5,8 +5,7 @@ :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.8.0"] [slingshot "0.12.2"]] - :profiles {:dev {:dependencies [[ring/ring-jetty-adapter "1.3.2"] - [ring/ring-devel "1.3.2"]]} + :profiles {:dev {:dependencies [[ring/ring-jetty-adapter "1.3.2"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} From 5239e5b8a26102827e26a902a8ba87cf6a0653d7 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 8 Jun 2021 23:54:43 +0200 Subject: [PATCH 031/143] Mark :test dependencies as such This tends to be cleaner - it's the "deps.edn" way. --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 987f03d0..4847c4e1 100644 --- a/project.clj +++ b/project.clj @@ -5,7 +5,7 @@ :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.8.0"] [slingshot "0.12.2"]] - :profiles {:dev {:dependencies [[ring/ring-jetty-adapter "1.3.2"]]} + :profiles {:test {:dependencies [[ring/ring-jetty-adapter "1.3.2"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} From 777f5c90f9929a8990a6fa6d606cc655fd7868c6 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 8 Jun 2021 23:55:45 +0200 Subject: [PATCH 032/143] `:test-selectors`: default to running all tests This is safer, especially for the CI integration. --- project.clj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/project.clj b/project.clj index 4847c4e1..771fa104 100644 --- a/project.clj +++ b/project.clj @@ -11,8 +11,9 @@ :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}} - :test-selectors {:default #(not (:integration %)) - :integration :integration - :all (constantly true)} + :test-selectors {:default (constantly true) + :all (constantly true) + :unit #(not (:integration %)) + :integration :integration} :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev,1.6:dev,1.7:dev,1.8:dev,1.9"]} :checksum-deps true) From f0b7aeb4b4d03e501d8f5d0c538d53077a365b65 Mon Sep 17 00:00:00 2001 From: vemv Date: Tue, 8 Jun 2021 23:57:21 +0200 Subject: [PATCH 033/143] Setup logging This silences Jetty logging, which can be otherwise noisy, especially when using the `:port 0` option. --- project.clj | 8 +++++++- test-resources/logback.xml | 17 +++++++++++++++++ test/setup.clj | 22 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 test-resources/logback.xml create mode 100644 test/setup.clj diff --git a/project.clj b/project.clj index 771fa104..a474fbe5 100644 --- a/project.clj +++ b/project.clj @@ -5,7 +5,13 @@ :url "http://www.opensource.org/licenses/mit-license.php"} :dependencies [[org.clojure/clojure "1.8.0"] [slingshot "0.12.2"]] - :profiles {:test {:dependencies [[ring/ring-jetty-adapter "1.3.2"]]} + :profiles {:test {:dependencies [[ring/ring-jetty-adapter "1.3.2"] + [ch.qos.logback/logback-classic "1.2.3" + :exclusions [org.slf4j/slf4j-api]] + [org.slf4j/jcl-over-slf4j "1.7.26"] + [org.slf4j/jul-to-slf4j "1.7.26"] + [org.slf4j/log4j-over-slf4j "1.7.26"]] + :resource-paths ["test-resources"]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} diff --git a/test-resources/logback.xml b/test-resources/logback.xml new file mode 100644 index 00000000..f45d53b7 --- /dev/null +++ b/test-resources/logback.xml @@ -0,0 +1,17 @@ + + + + + %d{ISO8601,Europe/London} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + diff --git a/test/setup.clj b/test/setup.clj new file mode 100644 index 00000000..0ced0c5e --- /dev/null +++ b/test/setup.clj @@ -0,0 +1,22 @@ +(ns setup + "This namespace will be automaticaly loaded by the test runner" + (:require + [clojure.string :as string]) + (:import + (org.eclipse.jetty.util MultiException))) + +(-> (reify Thread$UncaughtExceptionHandler + (uncaughtException [_ thread e] + ;; Omit exceptions coming from "Address already in use" because they're meaningless + ;; (these happen when one picks port 0, and after one such exception a new port will be retried successfully) + (let [omit? (and (instance? MultiException e) + (->> ^MultiException e + .getThrowables + (every? (fn [^Throwable t] + (-> t .getMessage (string/includes? "Address already in use"))))))] + (when-not omit? + (-> ^Throwable e .printStackTrace) + (when (System/getenv "CI") + (System/exit 1)))))) + + (Thread/setDefaultUncaughtExceptionHandler)) From 09207834c738cb514acd6f61a6864fc94d8c864d Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 00:00:46 +0200 Subject: [PATCH 034/143] Satisfy clj-kondo and Eastwood --- src/clj_http/lite/client.clj | 4 ++-- src/clj_http/lite/core.clj | 9 +++++---- test/clj_http/test/links_test.clj | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index f0aeda8d..a1e0805d 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -1,11 +1,11 @@ (ns clj-http.lite.client "Batteries-included HTTP client." - (:use [slingshot.slingshot :only [throw+]]) (:require [clojure.string :as str] [clojure.java.io :as io] [clj-http.lite.core :as core] [clj-http.lite.links :refer [wrap-links]] - [clj-http.lite.util :as util]) + [clj-http.lite.util :as util] + [slingshot.slingshot :refer [throw+]]) (:import (java.io InputStream File) (java.net URL UnknownHostException)) (:refer-clojure :exclude (get update))) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index a002df1f..0fadec47 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -47,8 +47,9 @@ (proxy [HostnameVerifier] [] (verify [^String hostname ^SSLSession session] true))) -(defn trust-invalid-manager [] +(defn trust-invalid-manager "This allows the ssl socket to connect with invalid/self-signed SSL certs." + [] (reify X509TrustManager (getAcceptedIssuers [this] nil) (checkClientTrusted [this certs authType]) @@ -69,13 +70,13 @@ uri (when query-string (str "?" query-string))) _ (when insecure? - (do (HttpsURLConnection/setDefaultSSLSocketFactory + (HttpsURLConnection/setDefaultSSLSocketFactory (.getSocketFactory (doto (SSLContext/getInstance "SSL") (.init nil (into-array TrustManager [(trust-invalid-manager)]) (new SecureRandom))))) - (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier)))) - ^HttpURLConnection conn (.openConnection ^URL (URL. http-url))] + (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))) + ^HttpURLConnection conn (.openConnection (URL. http-url))] (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" diff --git a/test/clj_http/test/links_test.clj b/test/clj_http/test/links_test.clj index 1813e9ee..f9128cf8 100644 --- a/test/clj_http/test/links_test.clj +++ b/test/clj_http/test/links_test.clj @@ -1,7 +1,7 @@ (ns clj-http.test.links-test "Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/test/clj_http/test/links_test.clj" - (:require [clj-http.lite.links :refer :all] - [clojure.test :refer :all])) + (:require [clj-http.lite.links :refer [wrap-links]] + [clojure.test :refer [deftest is testing]])) (defn- link-handler [link-header] (wrap-links (constantly {:headers {"link" link-header}}))) From 59396796bdc786201f6a7ba1a3e60bccd8647517 Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 00:09:33 +0200 Subject: [PATCH 035/143] Use randomized ports in tests This yields an overall cleaner pattern, avoiding a defonce, possible interference with other processes, etc. --- test/clj_http/test/client.clj | 18 +++--- test/clj_http/test/core.clj | 112 +++++++++++++++++----------------- 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index f81de0da..a8fa0910 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -1,26 +1,22 @@ (ns clj-http.test.client - (:use [clojure.test] - [clj-http.test.core :only [run-server]]) (:require [clj-http.lite.client :as client] - [clj-http.lite.util :as util]) + [clj-http.test.core :refer [base-req current-port with-server]] + [clj-http.lite.util :as util] + [clojure.test :refer [deftest is testing use-fixtures]]) (:import (java.net UnknownHostException) (java.util Arrays))) -(def base-req - {:scheme :http - :server-name "localhost" - :server-port 18080}) +(use-fixtures :each with-server) (deftest ^{:integration true} roundtrip - (run-server) - (Thread/sleep 1000) ;; roundtrip with scheme as a keyword - (let [resp (client/request (merge base-req {:uri "/get" :method :get}))] + (let [resp (client/request (merge (base-req) {:uri "/get" :method :get}))] (is (= 200 (:status resp))) #_(is (= "close" (get-in resp [:headers "connection"]))) (is (= "get" (:body resp)))) ;; roundtrip with scheme as a string - (let [resp (client/request (merge base-req {:uri "/get" :method :get + (let [resp (client/request (merge (base-req) {:uri "/get" + :method :get :scheme "http"}))] (is (= 200 (:status resp))) #_(is (= "close" (get-in resp [:headers "connection"]))) diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 66bb778f..8c7e6cff 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -1,15 +1,15 @@ (ns clj-http.test.core - (:use [clojure.test] - [clojure.java.io :only [file]]) - (:require [clojure.pprint :as pp] - [clj-http.lite.core :as core] + (:require [clj-http.lite.core :as core] [clj-http.lite.util :as util] + [clojure.pprint :as pp] + [clojure.java.io :refer [file]] + [clojure.test :refer [deftest is use-fixtures]] [ring.adapter.jetty :as ring]) - (:import (java.io ByteArrayInputStream))) + (:import (java.io ByteArrayInputStream) + (org.eclipse.jetty.server Server) + (org.eclipse.jetty.server.nio SelectChannelConnector))) (defn handler [req] - ;;(pp/pprint req) - ;;(println) (println) (condp = [(:request-method req) (:uri req)] [:get "/get"] {:status 200 :body "get"} @@ -33,86 +33,89 @@ [:post "/multipart"] {:status 200 :body (:body req)})) -(defn run-server - [] - (defonce server - (do - (future - (ring/run-jetty handler {:port 18080})) - (Thread/sleep 1000)))) +(defn make-server ^Server [] + (ring/run-jetty handler {:port 0 ;; Use a free port + :join? false})) + +(def ^:dynamic *server* nil) + +(defn current-port [] + (let [^Server s *server*] + (-> s .getConnectors ^SelectChannelConnector (first) .getLocalPort))) + +(defn with-server [t] + (let [s (make-server)] + (try + (binding [*server* s] + (t)) + (finally + (-> s .stop))))) -(def base-req - {:scheme :http - :server-name "localhost" - :server-port 18080}) +(use-fixtures :each with-server) + +(defn base-req [] + {:scheme :http + :server-name (str "localhost:" (current-port)) + :port (current-port)}) (defn request [req] - (core/request (merge base-req req))) + (core/request (merge (base-req) req))) (defn slurp-body [req] (slurp (:body req))) (deftest ^{:integration true} makes-get-request - (run-server) + (current-port) (let [resp (request {:request-method :get :uri "/get"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp))))) (deftest ^{:integration true} makes-head-request - (run-server) (let [resp (request {:request-method :head :uri "/head"})] (is (= 200 (:status resp))) (is (nil? (:body resp))))) (deftest ^{:integration true} sets-content-type-with-charset - (run-server) - (let [resp (request {:request-method :get :uri "/content-type" - :content-type "text/plain" :character-encoding "UTF-8"})] + (let [resp (request {:request-method :get :uri "/content-type" + :content-type "text/plain" :character-encoding "UTF-8"})] (is (= "text/plain; charset=UTF-8" (slurp-body resp))))) (deftest ^{:integration true} sets-content-type-without-charset - (run-server) (let [resp (request {:request-method :get :uri "/content-type" - :content-type "text/plain"})] + :content-type "text/plain"})] (is (= "text/plain" (slurp-body resp))))) (deftest ^{:integration true} sets-arbitrary-headers - (run-server) (let [resp (request {:request-method :get :uri "/header" - :headers {"X-My-Header" "header-val"}})] + :headers {"X-My-Header" "header-val"}})] (is (= "header-val" (slurp-body resp))))) (deftest ^{:integration true} sends-and-returns-byte-array-body - (run-server) (let [resp (request {:request-method :post :uri "/post" - :body (util/utf8-bytes "contents")})] + :body (util/utf8-bytes "contents")})] (is (= 200 (:status resp))) (is (= "contents" (slurp-body resp))))) (deftest ^{:integration true} returns-arbitrary-headers - (run-server) (let [resp (request {:request-method :get :uri "/get"})] (is (string? (get-in resp [:headers "date"]))))) (deftest ^{:integration true} returns-status-on-exceptional-responses - (run-server) (let [resp (request {:request-method :get :uri "/error"})] (is (= 500 (:status resp))))) (deftest ^{:integration true} returns-status-on-redirect - (run-server) (let [resp (request {:request-method :get :uri "/redirect" :follow-redirects false})] (is (= 302 (:status resp))))) (deftest ^{:integration true} auto-follows-on-redirect - (run-server) (let [resp (request {:request-method :get :uri "/redirect"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp))))) (deftest ^{:integration true} sets-conn-timeout - ; indirect way of testing if a connection timeout will fail by passing in an - ; invalid argument + ;; indirect way of testing if a connection timeout will fail by passing in an + ;; invalid argument (try (request {:request-method :get :uri "/timeout" :conn-timeout -1}) (throw (Exception. "Shouldn't get here.")) @@ -120,7 +123,6 @@ (is (= IllegalArgumentException (class e)))))) (deftest ^{:integration true} sets-socket-timeout - (run-server) (try (request {:request-method :get :uri "/timeout" :socket-timeout 1}) (throw (Exception. "Shouldn't get here.")) @@ -137,20 +139,20 @@ (deftest ^{:integration true} self-signed-ssl-get (let [t (doto (Thread. #(ring/run-jetty handler - {:port 8081 :ssl-port 18082 :ssl? true - :keystore "test-resources/keystore" + {:ssl? true + :keystore "test-resources/keystore" :key-password "keykey"})) .start)] (Thread/sleep 1000) (try (is (thrown? javax.net.ssl.SSLException (request {:request-method :get :uri "/get" - :server-port 18082 :scheme :https}))) - #_(let [resp (request {:request-method :get :uri "/get" :server-port 18082 - :scheme :https :insecure? true})] - (is (= 200 (:status resp))) - (is (= "get" (slurp-body resp)))) + :scheme :https}))) + #_(let [resp (request {:request-method :get :uri "/get" :server-port 18082 + :scheme :https :insecure? true})] + (is (= 200 (:status resp))) + (is (= "get" (slurp-body resp)))) (finally - (.stop t))))) + (.stop t))))) ;; (deftest ^{:integration true} multipart-form-uploads ;; (run-server) @@ -170,18 +172,19 @@ ;; (is (re-find #"name=\"d\"" resp-body)))) (deftest ^{:integration true} t-save-request-obj - (run-server) (let [resp (request {:request-method :post :uri "/post" - :body (.getBytes "foo bar") - :save-request? true})] + :body (.getBytes "foo bar") + :save-request? true})] (is (= 200 (:status resp))) - (is (= {:scheme :http - :http-url "http://localhost:18080/post" + (is (= {:scheme :http + :http-url (str "http://localhost:" (current-port) "/post") :request-method :post - :uri "/post" - :server-name "localhost" - :server-port 18080} - (dissoc (:request resp) :body))))) + :uri "/post" + :server-name (str "localhost:" (current-port)) + :port (current-port)} + (-> resp + :request + (dissoc :body)))))) ;; (deftest parse-headers ;; (are [headers expected] @@ -211,7 +214,6 @@ ;; "server" "some-server"})) (deftest ^{:integration true} t-streaming-response - (run-server) (let [stream (:body (request {:request-method :get :uri "/get" :as :stream})) body (slurp stream)] (is (= "get" body)))) From c26160273ccb541d306692e44d4e03879d6cfd2e Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 00:15:56 +0200 Subject: [PATCH 036/143] Remove some commented-out tests Persistent HTTP connections are not supported (per Readme.md) --- test/clj_http/test/client.clj | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index a8fa0910..a561e6b9 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -12,14 +12,12 @@ ;; roundtrip with scheme as a keyword (let [resp (client/request (merge (base-req) {:uri "/get" :method :get}))] (is (= 200 (:status resp))) - #_(is (= "close" (get-in resp [:headers "connection"]))) (is (= "get" (:body resp)))) ;; roundtrip with scheme as a string (let [resp (client/request (merge (base-req) {:uri "/get" :method :get :scheme "http"}))] (is (= 200 (:status resp))) - #_(is (= "close" (get-in resp [:headers "connection"]))) (is (= "get" (:body resp))))) (defn is-passed [middleware req] From ea29cd7fcc81c0ef35fd1d9b64e7e0111753e823 Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 01:31:17 +0200 Subject: [PATCH 037/143] Enable test exercising `:insecure?` again --- test-resources/logback.xml | 2 ++ test/clj_http/test/core.clj | 50 +++++++++++++++++++++++-------------- test/setup.clj | 11 ++++---- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/test-resources/logback.xml b/test-resources/logback.xml index f45d53b7..bee31b99 100644 --- a/test-resources/logback.xml +++ b/test-resources/logback.xml @@ -13,5 +13,7 @@ + + diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 8c7e6cff..f8a96cc4 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -7,7 +7,8 @@ [ring.adapter.jetty :as ring]) (:import (java.io ByteArrayInputStream) (org.eclipse.jetty.server Server) - (org.eclipse.jetty.server.nio SelectChannelConnector))) + (org.eclipse.jetty.server.nio SelectChannelConnector) + (org.eclipse.jetty.server.ssl SslSelectChannelConnector))) (defn handler [req] (condp = [(:request-method req) (:uri req)] @@ -34,14 +35,30 @@ {:status 200 :body (:body req)})) (defn make-server ^Server [] - (ring/run-jetty handler {:port 0 ;; Use a free port - :join? false})) + (ring/run-jetty handler {:port 0 ;; Use a free port + :join? false + :ssl-port 0 ;; Use a free port + :ssl? true + :keystore "test-resources/keystore" + :key-password "keykey"})) (def ^:dynamic *server* nil) (defn current-port [] (let [^Server s *server*] - (-> s .getConnectors ^SelectChannelConnector (first) .getLocalPort))) + (->> s + .getConnectors + (filter (comp #{SelectChannelConnector} class)) + ^SelectChannelConnector (first) + .getLocalPort))) + +(defn current-https-port [] + (let [^Server s *server*] + (->> s + .getConnectors + (filter (comp #{SslSelectChannelConnector} class)) + ^SslSelectChannelConnector (first) + .getLocalPort))) (defn with-server [t] (let [s (make-server)] @@ -138,21 +155,16 @@ ;; (is (= 200 (:status resp))))) (deftest ^{:integration true} self-signed-ssl-get - (let [t (doto (Thread. #(ring/run-jetty handler - {:ssl? true - :keystore "test-resources/keystore" - :key-password "keykey"})) .start)] - (Thread/sleep 1000) - (try - (is (thrown? javax.net.ssl.SSLException - (request {:request-method :get :uri "/get" - :scheme :https}))) - #_(let [resp (request {:request-method :get :uri "/get" :server-port 18082 - :scheme :https :insecure? true})] - (is (= 200 (:status resp))) - (is (= "get" (slurp-body resp)))) - (finally - (.stop t))))) + (let [client-opts {:request-method :get + :uri "/get" + :scheme :https + :server-name (str "localhost:" (current-https-port)) + :port (current-https-port)}] + (is (thrown? javax.net.ssl.SSLException + (request client-opts))) + (let [resp (request (assoc client-opts :insecure? true))] + (is (= 200 (:status resp))) + (is (= "get" (slurp-body resp)))))) ;; (deftest ^{:integration true} multipart-form-uploads ;; (run-server) diff --git a/test/setup.clj b/test/setup.clj index 0ced0c5e..0c960c7f 100644 --- a/test/setup.clj +++ b/test/setup.clj @@ -9,11 +9,12 @@ (uncaughtException [_ thread e] ;; Omit exceptions coming from "Address already in use" because they're meaningless ;; (these happen when one picks port 0, and after one such exception a new port will be retried successfully) - (let [omit? (and (instance? MultiException e) - (->> ^MultiException e - .getThrowables - (every? (fn [^Throwable t] - (-> t .getMessage (string/includes? "Address already in use"))))))] + (let [omit? (or (-> ^Throwable e .getMessage #{"Address already in use"}) + (and (instance? MultiException e) + (->> ^MultiException e + .getThrowables + (every? (fn [^Throwable t] + (-> t .getMessage (string/includes? "Address already in use")))))))] (when-not omit? (-> ^Throwable e .printStackTrace) (when (System/getenv "CI") From 6f228c35c3a559326a3d4ad302ffe16abe460e26 Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 01:35:24 +0200 Subject: [PATCH 038/143] Remove references to unsupported :multipart option Closes https://github.com/martinklepsch/clj-http-lite/issues/5 --- Readme.md | 9 --------- src/clj_http/lite/core.clj | 2 +- test/clj_http/test/core.clj | 21 +-------------------- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/Readme.md b/Readme.md index dbe0a6d3..28ea4c8d 100644 --- a/Readme.md +++ b/Readme.md @@ -72,15 +72,6 @@ More example requests: ;; Send form params as a urlencoded body (client/post "http//site.com" {:form-params {:foo "bar"}}) -;; Multipart form uploads/posts -;; a map or vector works as the multipart object. Use a vector of -;; vectors if you need to preserve order, a map otherwise. -(client/post "http//example.org" {:multipart [["title" "My Awesome Picture"] - ["Content/type" "image/jpeg"] - ["file" (clojure.java.io/file "pic.jpg")]]}) -;; Multipart values can be one of the following: -;; String, InputStream, File, or a byte-array - ;; Basic authentication (client/get "http://site.com/protected" {:basic-auth ["user" "pass"]}) (client/get "http://site.com/protected" {:basic-auth "user:pass"}) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 0fadec47..80a87398 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -63,7 +63,7 @@ the clj-http uses ByteArrays for the bodies." [{:keys [request-method scheme server-name server-port uri query-string headers content-type character-encoding body socket-timeout - conn-timeout multipart debug insecure? save-request? follow-redirects + conn-timeout debug insecure? save-request? follow-redirects chunk-size] :as req}] (let [http-url (str (name scheme) "://" server-name (when server-port (str ":" server-port)) diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index f8a96cc4..75718d9a 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -30,9 +30,7 @@ (Thread/sleep 10) {:status 200 :body "timeout"}) [:delete "/delete-with-body"] - {:status 200 :body "delete-with-body"} - [:post "/multipart"] - {:status 200 :body (:body req)})) + {:status 200 :body "delete-with-body"})) (defn make-server ^Server [] (ring/run-jetty handler {:port 0 ;; Use a free port @@ -166,23 +164,6 @@ (is (= 200 (:status resp))) (is (= "get" (slurp-body resp)))))) -;; (deftest ^{:integration true} multipart-form-uploads -;; (run-server) -;; (let [bytes (util/utf8-bytes "byte-test") -;; stream (ByteArrayInputStream. bytes) -;; resp (request {:request-method :post :uri "/multipart" -;; :multipart [["a" "testFINDMEtest"] -;; ["b" bytes] -;; ["c" stream] -;; ["d" (file "test-resources/keystore")]]}) -;; resp-body (apply str (map #(try (char %) (catch Exception _ "")) -;; (:body resp)))] -;; (is (= 200 (:status resp))) -;; (is (re-find #"testFINDMEtest" resp-body)) -;; (is (re-find #"byte-test" resp-body)) -;; (is (re-find #"name=\"c\"" resp-body)) -;; (is (re-find #"name=\"d\"" resp-body)))) - (deftest ^{:integration true} t-save-request-obj (let [resp (request {:request-method :post :uri "/post" :body (.getBytes "foo bar") From 07826dc421476917c75511cbd7476e2bc2ffc849 Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 9 Jun 2021 04:59:35 +0200 Subject: [PATCH 039/143] Set up a test matrix --- .circleci/config.yml | 68 +++++++++++++++++++++++++++++++++++ .travis.yml | 1 - project.clj | 6 ++-- test/clj_http/test/client.clj | 2 +- test/clj_http/test/core.clj | 1 - test/setup.clj | 2 +- 6 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .travis.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..134c447d --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,68 @@ +version: 2.1 + +executor_defaults: &executor_defaults + working_directory: ~/repo + +# We exercise the following JVMs: +# * those officially supported by Clojure (atm: 8 and 11) +# * plus, whatever the latest version is. +executors: + openjdk8: + docker: + - image: circleci/clojure:openjdk-8-lein-2.9.5 + environment: + LEIN_ROOT: "true" + JVM_OPTS: -Xmx3200m + <<: *executor_defaults + openjdk11: + docker: + - image: circleci/clojure:openjdk-11-lein-2.9.5 + environment: + LEIN_ROOT: "true" + JVM_OPTS: -Xmx3200m --illegal-access=deny + <<: *executor_defaults + openjdk16: + docker: + - image: circleci/clojure:openjdk-16-lein-2.9.5-buster + environment: + LEIN_ROOT: "true" + JVM_OPTS: -Xmx3200m --illegal-access=deny + <<: *executor_defaults + +jobs: + test: + parameters: + executor: + type: executor + clojure-version: + type: string + executor: << parameters.executor >> + steps: + - checkout + + - restore_cache: + keys: + - v1-dependencies-{{ checksum "project.clj" }} + + - run: + name: Fetch dependencies + command: | + lein with-profile +test deps + + - save_cache: + paths: + - ~/.m2 + key: v1-dependencies-{{ checksum "project.clj" }} + + - run: + name: Run test suite + command: lein with-profile -user,-dev,+test,+<< parameters.clojure-version >> do clean, test + +workflows: + default: + jobs: + - test: + matrix: + parameters: + executor: [openjdk8, openjdk11, openjdk16] + clojure-version: ["1.7", "1.8", "1.9", "1.10"] diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 07913052..00000000 --- a/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: clojure diff --git a/project.clj b/project.clj index a474fbe5..d9a4b372 100644 --- a/project.clj +++ b/project.clj @@ -12,14 +12,12 @@ [org.slf4j/jul-to-slf4j "1.7.26"] [org.slf4j/log4j-over-slf4j "1.7.26"]] :resource-paths ["test-resources"]} - :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} - :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} - :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}} + :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]} + :1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}} :test-selectors {:default (constantly true) :all (constantly true) :unit #(not (:integration %)) :integration :integration} - :aliases {"all" ["with-profile" "dev,1.4:dev,1.5:dev,1.6:dev,1.7:dev,1.8:dev,1.9"]} :checksum-deps true) diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index a561e6b9..f81ebcf7 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -16,7 +16,7 @@ ;; roundtrip with scheme as a string (let [resp (client/request (merge (base-req) {:uri "/get" :method :get - :scheme "http"}))] + :scheme "http"}))] (is (= 200 (:status resp))) (is (= "get" (:body resp))))) diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 75718d9a..3c81b9e8 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -80,7 +80,6 @@ (slurp (:body req))) (deftest ^{:integration true} makes-get-request - (current-port) (let [resp (request {:request-method :get :uri "/get"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp))))) diff --git a/test/setup.clj b/test/setup.clj index 0c960c7f..976a6f79 100644 --- a/test/setup.clj +++ b/test/setup.clj @@ -14,7 +14,7 @@ (->> ^MultiException e .getThrowables (every? (fn [^Throwable t] - (-> t .getMessage (string/includes? "Address already in use")))))))] + (-> t .getMessage (.contains "Address already in use")))))))] (when-not omit? (-> ^Throwable e .printStackTrace) (when (System/getenv "CI") From f918418f911348c93eb1b3433904c454687bb25a Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 16 Jun 2021 05:40:53 +0200 Subject: [PATCH 040/143] Remove .circleci config file I added it because I thought I was replacing the old Travis file, however I didn't notice there was already a GH Actions file. --- .circleci/config.yml | 68 -------------------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 134c447d..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,68 +0,0 @@ -version: 2.1 - -executor_defaults: &executor_defaults - working_directory: ~/repo - -# We exercise the following JVMs: -# * those officially supported by Clojure (atm: 8 and 11) -# * plus, whatever the latest version is. -executors: - openjdk8: - docker: - - image: circleci/clojure:openjdk-8-lein-2.9.5 - environment: - LEIN_ROOT: "true" - JVM_OPTS: -Xmx3200m - <<: *executor_defaults - openjdk11: - docker: - - image: circleci/clojure:openjdk-11-lein-2.9.5 - environment: - LEIN_ROOT: "true" - JVM_OPTS: -Xmx3200m --illegal-access=deny - <<: *executor_defaults - openjdk16: - docker: - - image: circleci/clojure:openjdk-16-lein-2.9.5-buster - environment: - LEIN_ROOT: "true" - JVM_OPTS: -Xmx3200m --illegal-access=deny - <<: *executor_defaults - -jobs: - test: - parameters: - executor: - type: executor - clojure-version: - type: string - executor: << parameters.executor >> - steps: - - checkout - - - restore_cache: - keys: - - v1-dependencies-{{ checksum "project.clj" }} - - - run: - name: Fetch dependencies - command: | - lein with-profile +test deps - - - save_cache: - paths: - - ~/.m2 - key: v1-dependencies-{{ checksum "project.clj" }} - - - run: - name: Run test suite - command: lein with-profile -user,-dev,+test,+<< parameters.clojure-version >> do clean, test - -workflows: - default: - jobs: - - test: - matrix: - parameters: - executor: [openjdk8, openjdk11, openjdk16] - clojure-version: ["1.7", "1.8", "1.9", "1.10"] From 3b5fc28ff05cfcaaeb0f439cfa81eec7c1bb6999 Mon Sep 17 00:00:00 2001 From: vemv Date: Wed, 16 Jun 2021 05:41:06 +0200 Subject: [PATCH 041/143] GH Actions: introduce a test matrix --- .github/workflows/ci.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3004662..7de1c9b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,24 @@ name: Tests -on: [push] +on: [push, pull_request] jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + clojure-version: ["1.7", "1.8", "1.9", "1.10"] + java-version: ["8", "11", "16"] steps: - name: Prepare java - uses: actions/setup-java@v1 + uses: actions/setup-java@v2 with: - java-version: 1.8 + distribution: "adopt" + java-version: ${{ matrix.java-version }} - name: Setup Clojure - uses: DeLaGuardo/setup-clojure@2.0 + uses: DeLaGuardo/setup-clojure@3.4 with: - lein: 2.9.1 + lein: 2.9.4 - name: Checkout uses: actions/checkout@v2-beta - name: Run tests - run: lein test :all + run: lein with-profile -user,-dev,+test,+${{ matrix.clojure-version }} do clean, test From bb10221cd823cacf2ecaef6e5588a6bb3e1efe39 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 07:30:33 +0100 Subject: [PATCH 042/143] Add initial build.clj --- build.clj | 32 ++++++++++++++++++++++++++++++++ deps.edn | 7 ++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 build.clj diff --git a/build.clj b/build.clj new file mode 100644 index 00000000..9d42c9c0 --- /dev/null +++ b/build.clj @@ -0,0 +1,32 @@ +(ns build + (:require [clojure.tools.build.api :as b])) + +(def lib 'org.clj-commons/clj-http-lite) +(def version (format "0.4.%s" (b/git-count-revs nil))) +(def class-dir "target/classes") +(def basis (b/create-basis {:project "deps.edn"})) +(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version)) +(def jar-file (format "target/%s-%s.jar" (name lib) version)) + +(defn clean [_] + (b/delete {:path "target"})) + +(defn jar [_] + (b/write-pom {:class-dir class-dir + :lib lib + :version version + :basis basis + :src-dirs ["src"]}) + (b/copy-dir {:src-dirs ["src" "resources"] + :target-dir class-dir}) + (b/jar {:class-dir class-dir + :jar-file jar-file})) + +(defn deploy [opts] + (jar opts) + ((requiring-resolve 'deps-deploy.deps-deploy/deploy) + (merge {:installer :remote + :artifact jar-file + :pom-file (b/pom-path {:lib lib :class-dir class-dir})} + opts)) + opts) diff --git a/deps.edn b/deps.edn index 934123d7..b35b6cfa 100644 --- a/deps.edn +++ b/deps.edn @@ -1,2 +1,7 @@ {:paths ["src"] - :deps {org.clojure/clojure {:mvn/version "1.10.0"}}} + :deps {org.clojure/clojure {:mvn/version "1.10.0"}} + :aliases + {:build + {:deps {io.github.clojure/tools.build {:git/tag "v0.6.6" :git/sha "4d41c26"} + slipset/deps-deploy {:mvn/version "0.2.0"}} + :ns-default build}}} From 38f7bfd30c3e299a052c6a1497371b7b06ef5323 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 07:37:54 +0100 Subject: [PATCH 043/143] Add maybe-deploy --- .gitignore | 2 ++ build.clj | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 70a8bead..51c74c0e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ aws.clj *.pyc .lein-failures /.lein-deps-sum +.cache +.cpcache diff --git a/build.clj b/build.clj index 9d42c9c0..1bbe4933 100644 --- a/build.clj +++ b/build.clj @@ -1,5 +1,6 @@ (ns build - (:require [clojure.tools.build.api :as b])) + (:require [clojure.string :as str] + [clojure.tools.build.api :as b])) (def lib 'org.clj-commons/clj-http-lite) (def version (format "0.4.%s" (b/git-count-revs nil))) @@ -22,6 +23,11 @@ (b/jar {:class-dir class-dir :jar-file jar-file})) +(def release-marker "Release-") + +(defn extract-version [tag] + (str/replace-first tag release-marker "")) + (defn deploy [opts] (jar opts) ((requiring-resolve 'deps-deploy.deps-deploy/deploy) @@ -30,3 +36,20 @@ :pom-file (b/pom-path {:lib lib :class-dir class-dir})} opts)) opts) + +(defn maybe-deploy [opts] + (if-let [tag (System/getenv "CIRCLE_TAG")] + (do + (println "Found tag " tag) + (if (re-find (re-pattern release-marker) tag) + (do + (println "Releasing to clojars...") + (-> opts + (assoc :lib lib :version (extract-version tag)) + (deploy))) + (do + (println "Tag is not a release tag, skipping deploy") + opts))) + (do + (println "No tag found, skipping deploy") + opts))) From fc135cb4f8351c87235738ef2d390d14517eb26d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 07:40:13 +0100 Subject: [PATCH 044/143] clean --- build.clj | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.clj b/build.clj index 1bbe4933..8f675b51 100644 --- a/build.clj +++ b/build.clj @@ -6,7 +6,6 @@ (def version (format "0.4.%s" (b/git-count-revs nil))) (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) -(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version)) (def jar-file (format "target/%s-%s.jar" (name lib) version)) (defn clean [_] @@ -23,11 +22,6 @@ (b/jar {:class-dir class-dir :jar-file jar-file})) -(def release-marker "Release-") - -(defn extract-version [tag] - (str/replace-first tag release-marker "")) - (defn deploy [opts] (jar opts) ((requiring-resolve 'deps-deploy.deps-deploy/deploy) @@ -37,6 +31,11 @@ opts)) opts) +(def release-marker "Release-") + +(defn extract-version [tag] + (str/replace-first tag release-marker "")) + (defn maybe-deploy [opts] (if-let [tag (System/getenv "CIRCLE_TAG")] (do From ba25d96dbd55da67aa6fd90f978afceaf572259b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 08:01:27 +0100 Subject: [PATCH 045/143] Add test runner --- deps.edn | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/deps.edn b/deps.edn index b35b6cfa..04024522 100644 --- a/deps.edn +++ b/deps.edn @@ -4,4 +4,16 @@ {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.6.6" :git/sha "4d41c26"} slipset/deps-deploy {:mvn/version "0.2.0"}} - :ns-default build}}} + :ns-default build} + :test + {:extra-paths ["test" "test-resources"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.0" :git/sha "b3fd0d2"} + ring/ring-jetty-adapter {:mvn/version "1.3.2"} + ch.qos.logback/logback-classic {:mvn/version "1.2.3" + :exclusions [org.slf4j/slf4j-api]} + org.slf4j/jcl-over-slf4j {:mvn/version "1.7.26"} + org.slf4j/jul-to-slf4j {:mvn/version "1.7.26"} + org.slf4j/log4j-over-slf4j {:mvn/version "1.7.26"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test}}} From 4f2e2a8a189a1428b64d7deae5c5b7a2df1a4f91 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 13:24:32 +0100 Subject: [PATCH 046/143] [#10] Remove slingshot, use ex-info --- project.clj | 3 +-- src/clj_http/lite/client.clj | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/project.clj b/project.clj index d9a4b372..eed500e6 100644 --- a/project.clj +++ b/project.clj @@ -3,8 +3,7 @@ :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" :url "http://www.opensource.org/licenses/mit-license.php"} - :dependencies [[org.clojure/clojure "1.8.0"] - [slingshot "0.12.2"]] + :dependencies [[org.clojure/clojure "1.8.0"]] :profiles {:test {:dependencies [[ring/ring-jetty-adapter "1.3.2"] [ch.qos.logback/logback-classic "1.2.3" :exclusions [org.slf4j/slf4j-api]] diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index a1e0805d..d4261f2d 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -4,8 +4,7 @@ [clojure.java.io :as io] [clj-http.lite.core :as core] [clj-http.lite.links :refer [wrap-links]] - [clj-http.lite.util :as util] - [slingshot.slingshot :refer [throw+]]) + [clj-http.lite.util :as util]) (:import (java.io InputStream File) (java.net URL UnknownHostException)) (:refer-clojure :exclude (get update))) @@ -36,7 +35,7 @@ (if (or (not (clojure.core/get req :throw-exceptions true)) (unexceptional-status? status)) resp - (throw+ resp "clj-http: status %s" (:status %)))))) + (throw (ex-info (str "clj-http: status " (:status resp)) resp)))))) (declare wrap-redirects) From b02f53e58539f7ac414d02aa33ea02bb4abddc53 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 13:32:06 +0100 Subject: [PATCH 047/143] [#10] README update --- Readme.md | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/Readme.md b/Readme.md index 28ea4c8d..37985fd1 100644 --- a/Readme.md +++ b/Readme.md @@ -144,32 +144,29 @@ as a primitive for building higher-level interfaces: ### Exceptions The client will throw exceptions on, well, exceptional status -codes. clj-http will throw a -[Slingshot](http://github.com/scgilardi/slingshot) Stone that can be -caught by a regular `(catch Exception e ...)` or in Slingshot's `try+` -block: +codes. clj-http will throw an `ex-info` with the response as `ex-data`. ```clojure -(client/get "http://site.com/broken") -=> Stone Object thrown by throw+: {:status 404, :headers {"server" "nginx/1.0.4", - "x-runtime" "12ms", - "content-encoding" "gzip", - "content-type" "text/html; charset=utf-8", - "date" "Mon, 17 Oct 2011 23:15 :36 GMT", - "cache-control" "no-cache", - "status" "404 Not Found", - "transfer-encoding" "chunked", - "connection" "close"}, - :body "...body here..."} - clj-http.lite.client/wrap-exceptions/fn--227 (client.clj:37) - -;; You can also ignore exceptions and handle them yourself: +user=> (client/get "http://site.com/broken") +Execution error (ExceptionInfo) at clj-http.lite.client/wrap-exceptions$fn (client.clj:38). +clj-http: status 404 +user=> (-> *e ex-data :status) +404 +user=> (-> *e ex-data keys) +(:headers :status :body) +``` + +You can also ignore exceptions and handle them yourself: + +``` clojure (client/get "http://site.com/broken" {:throw-exceptions false}) -;; Or ignore an unknown host (methods return 'nil' if this is set to -;; true and the host does not exist: +``` + +Or ignore an unknown host (methods return 'nil' if this is set to true and the host does not exist: + +``` clojure (client/get "http://aoeuntahuf89o.com" {:ignore-unknown-host? true}) -```` -(spacing added by me to be human readable) +``` ### Proxies From 207552963eba77cd9ac8ae1c353e279408f47b1c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 13:34:02 +0100 Subject: [PATCH 048/143] CHANGELOG [skip ci] --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed54f0dd..bfb259d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ### unreleased -Update to support self-signed certificates via insecure? option + +- Support self-signed certificates via `:insecure? true` option +- Remove dependency on Slingshot ### 0.4.3 From 0fec63c089ead74f54b97c7ebd9d94ae9f3743cd Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 13:37:08 +0100 Subject: [PATCH 049/143] Add CODEOWNERS --- .github/CODEOWNERS | 1 + CHANGELOG.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..5cfcee2c --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +@borkdude @martinklepsch @slipset diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb259d5..72e10193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### unreleased +### Unreleased - Support self-signed certificates via `:insecure? true` option - Remove dependency on Slingshot @@ -9,7 +9,7 @@ ### 0.4.2 -- Add type hints for GraalVM ([#2](https://github.com/martinklepsch/clj-http-lite/pull/2)) +- Add type hints for GraalVM ([#2](https://github.com/clj-commons/clj-http-lite/pull/2)) ### 0.4.0 From d6930867247c216fdc41c409ec5f2c9e71fa8651 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 13:38:16 +0100 Subject: [PATCH 050/143] README [skip ci] --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 37985fd1..ef69a46c 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. -> This is a somewhat maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. +> This is a clj-commons maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. [Installation](#installation) | [Usage](#usage) | [Known Issues](#known-issues) | [Design](#design) | [Development](#development) From f8c1622e0ce63842f91663f979d6b1be825b3af4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 14:03:15 +0100 Subject: [PATCH 051/143] Babashka compatibility --- bb.edn | 7 +++++ bb/clj_http/lite/client_test.clj | 31 +++++++++++++++++++ bb/clj_http/lite/test_runner.clj | 10 ++++++ deps.edn | 2 +- src/clj_http/lite/client.clj | 15 +++++---- src/clj_http/lite/core.clj | 52 ++++++++++++++++++++------------ src/clj_http/lite/util.clj | 2 +- 7 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 bb.edn create mode 100644 bb/clj_http/lite/client_test.clj create mode 100644 bb/clj_http/lite/test_runner.clj diff --git a/bb.edn b/bb.edn new file mode 100644 index 00000000..dd3f565f --- /dev/null +++ b/bb.edn @@ -0,0 +1,7 @@ +{:paths ["bb"] + :deps {org.clj-commons/clj-http-lite {:local/root "."}} + :tasks + {test:clj {:doc "Run Clojure tests" + :task (clojure "-M:test")} + test:bb {:doc "Run babashka tests" + :task clj-http.lite.test-runner/-main}}} diff --git a/bb/clj_http/lite/client_test.clj b/bb/clj_http/lite/client_test.clj new file mode 100644 index 00000000..3a0055ba --- /dev/null +++ b/bb/clj_http/lite/client_test.clj @@ -0,0 +1,31 @@ +(ns clj-http.lite.client-test + (:require [cheshire.core :as json] + [clj-http.lite.client :as client] + [clojure.test :as t :refer [deftest is]])) + +(deftest client-test + (is (= 200 (:status (client/get "https://www.clojure.org" {:throw-exceptions false})))) + + (is (= 200 (:status (client/get "https://postman-echo.com/get?foo1=bar1&foo2=bar2" {:throw-exceptions false})))) + + (is (= 200 (:status (client/post "https://postman-echo.com/post" {:throw-exceptions false})))) + + (is (= 200 (:status (client/post "https://postman-echo.com/post" + {:body (json/generate-string {:a 1}) + :headers {"X-Hasura-Role" "admin"} + :content-type :json + :accept :json + :throw-exceptions false})))) + + (is (= 200 (:status (client/put "https://postman-echo.com/put" + {:body (json/generate-string {:a 1}) + :headers {"X-Hasura-Role" "admin"} + :content-type :json + :accept :json + :throw-exceptions false}))))) + +(deftest exception-test + (try (client/get "https://site.com/broken") + (is false "should not reach here") + (catch Exception e + (is (:headers (ex-data e)))))) diff --git a/bb/clj_http/lite/test_runner.clj b/bb/clj_http/lite/test_runner.clj new file mode 100644 index 00000000..b793c578 --- /dev/null +++ b/bb/clj_http/lite/test_runner.clj @@ -0,0 +1,10 @@ +(ns clj-http.lite.test-runner + (:require [clj-http.lite.client-test] + [clojure.test :as t])) + +(defn -main [& _] + (let [{:keys [fail error]} (t/run-tests 'clj-http.lite.client-test)] + (System/exit (if (or (pos? fail) + (pos? error)) + 1 0)))) + diff --git a/deps.edn b/deps.edn index 04024522..96f0cb2c 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,5 @@ {:paths ["src"] - :deps {org.clojure/clojure {:mvn/version "1.10.0"}} + :deps {org.clojure/clojure {:mvn/version "1.8.0"}} :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.6.6" :git/sha "4d41c26"} diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index d4261f2d..57637d61 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -1,12 +1,11 @@ (ns clj-http.lite.client "Batteries-included HTTP client." - (:require [clojure.string :as str] - [clojure.java.io :as io] - [clj-http.lite.core :as core] + (:require [clj-http.lite.core :as core] [clj-http.lite.links :refer [wrap-links]] - [clj-http.lite.util :as util]) - (:import (java.io InputStream File) - (java.net URL UnknownHostException)) + [clj-http.lite.util :as util] + [clojure.java.io :as io] + [clojure.string :as str]) + (:import (java.net UnknownHostException)) (:refer-clojure :exclude (get update))) (set! *warn-on-reflection* true) @@ -104,7 +103,7 @@ resp)))) (defn wrap-input-coercion [client] - (fn [{:keys [body body-encoding length] :as req}] + (fn [{:keys [body body-encoding _length] :as req}] (if body (cond (string? body) @@ -296,6 +295,6 @@ (defmacro with-connection-pool "This macro is a no-op, but left in to support backward-compatibility with clj-http." - [opts & body] + [_opts & body] `(do ~@body)) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 80a87398..007f5df9 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -1,9 +1,8 @@ (ns clj-http.lite.core "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) - (:import (java.io ByteArrayOutputStream InputStream IOException) + (:import (java.io ByteArrayOutputStream InputStream) (java.net URL HttpURLConnection) - (javax.net.ssl HttpsURLConnection SSLContext TrustManager X509TrustManager HostnameVerifier SSLSession) (java.security SecureRandom))) (set! *warn-on-reflection* true) @@ -33,7 +32,7 @@ [{:keys [as]} conn] (let [ins (try (.getInputStream ^HttpURLConnection conn) - (catch Exception e + (catch Exception _e (.getErrorStream ^HttpURLConnection conn)))] (if (or (= :stream as) (nil? ins)) ins @@ -43,17 +42,37 @@ (.flush baos) (.toByteArray baos))))) -(defn my-host-verifier [] - (proxy [HostnameVerifier] [] - (verify [^String hostname ^SSLSession session] true))) +(def ^:private insecure-mode + (delay (throw (ex-info "insecure? option not supported in this environment" + {})))) -(defn trust-invalid-manager - "This allows the ssl socket to connect with invalid/self-signed SSL certs." - [] - (reify X509TrustManager - (getAcceptedIssuers [this] nil) - (checkClientTrusted [this certs authType]) - (checkServerTrusted [this certs authType]))) +(defmacro ^:private def-insecure [] + (when (try (import '[javax.net.ssl + HttpsURLConnection SSLContext TrustManager X509TrustManager HostnameVerifier SSLSession]) + (catch Exception _)) + '(do + (defn- my-host-verifier [] + (proxy [HostnameVerifier] [] + (verify [^String hostname ^javax.net.ssl.SSLSession session] true))) + + (defn trust-invalid-manager + "This allows the ssl socket to connect with invalid/self-signed SSL certs." + [] + (reify javax.net.ssl.X509TrustManager + (getAcceptedIssuers [this] nil) + (checkClientTrusted [this certs authType]) + (checkServerTrusted [this certs authType]))) + + (def ^:private insecure-mode + (delay + (HttpsURLConnection/setDefaultSSLSocketFactory + (.getSocketFactory + (doto (SSLContext/getInstance "SSL") + (.init nil (into-array TrustManager [(trust-invalid-manager)]) + (new java.security.SecureRandom))))) + (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))))))) + +(def-insecure) (defn request "Executes the HTTP request corresponding to the given Ring request map and @@ -70,12 +89,7 @@ uri (when query-string (str "?" query-string))) _ (when insecure? - (HttpsURLConnection/setDefaultSSLSocketFactory - (.getSocketFactory - (doto (SSLContext/getInstance "SSL") - (.init nil (into-array TrustManager [(trust-invalid-manager)]) - (new SecureRandom))))) - (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))) + @insecure-mode) ^HttpURLConnection conn (.openConnection (URL. http-url))] (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index 32b65232..6e143c81 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -34,7 +34,7 @@ "Encode an array of bytes into a base64 encoded string." [unencoded] (if (try (import 'javax.xml.bind.DatatypeConverter) - (catch ClassNotFoundException _)) + (catch Exception _)) `(javax.xml.bind.DatatypeConverter/printBase64Binary ~unencoded) (do (import 'java.util.Base64) From fc1c2a1dbce7a43bca1a01d755f2687bf9eee8e7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 14:16:09 +0100 Subject: [PATCH 052/143] Add babashka test --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7de1c9b8..128e300b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,3 +22,13 @@ jobs: uses: actions/checkout@v2-beta - name: Run tests run: lein with-profile -user,-dev,+test,+${{ matrix.clojure-version }} do clean, test + bb-test: + runs-on: ubuntu-latest + steps: + - name: Setup Babashka + uses: turtlequeue/setup-babashka@v1.3.0 + with: + babashka-version: 0.6.4 + + - name: tests + run: bb test:bb From 51fbbc48eec2d4449469a14c91401a41853b74b1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 14:17:35 +0100 Subject: [PATCH 053/143] Check out before running bb --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 128e300b..b6a0ee23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,8 @@ jobs: bb-test: runs-on: ubuntu-latest steps: + - name: Checkout + uses: actions/checkout@v2-beta - name: Setup Babashka uses: turtlequeue/setup-babashka@v1.3.0 with: From e383cb646dd48d538b2a1992a8f4a7e87ff3cac0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 14:41:07 +0100 Subject: [PATCH 054/143] Deploy config --- .github/workflows/ci.yml | 15 +++++++++++++++ build.clj | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6a0ee23..659a2d81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,3 +34,18 @@ jobs: - name: tests run: bb test:bb + deploy: + runs-on: ubuntu-latest + needs: + - test + - bb-test + steps: + - name: Checkout + uses: actions/checkout@v2-beta + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@3.5 + with: + # Install just one or all simultaneously + cli: 1.10.3.1029 # Clojure CLI based on tools.deps + - name: Deploy + run: clojure -T:build maybe-deploy diff --git a/build.clj b/build.clj index 8f675b51..59dbfef9 100644 --- a/build.clj +++ b/build.clj @@ -36,8 +36,12 @@ (defn extract-version [tag] (str/replace-first tag release-marker "")) +(defn ci-tag [] + (when (= "tag" (System/getenv "GITHUB_REF_TYPE")) + (System/getenv "GITHUB_REF_NAME"))) + (defn maybe-deploy [opts] - (if-let [tag (System/getenv "CIRCLE_TAG")] + (if-let [tag (ci-tag)] (do (println "Found tag " tag) (if (re-find (re-pattern release-marker) tag) From 4cd7956622207c456857d9835bf0dbf619371b3d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:08:02 +0100 Subject: [PATCH 055/143] bb config --- bb.edn | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/bb.edn b/bb.edn index dd3f565f..427e24ce 100644 --- a/bb.edn +++ b/bb.edn @@ -1,7 +1,29 @@ {:paths ["bb"] - :deps {org.clj-commons/clj-http-lite {:local/root "."}} + :deps {org.clj-commons/clj-http-lite {:local/root "."} + org.clj-commons/infra {:git/url "https://github.com/clj-commons/infra" + :git/sha "a3ebcff4d32c4b84f001f86cdee5c76358d15ea5"}} :tasks {test:clj {:doc "Run Clojure tests" :task (clojure "-M:test")} test:bb {:doc "Run babashka tests" - :task clj-http.lite.test-runner/-main}}} + :task clj-http.lite.test-runner/-main} + deploy + {:requires ([clojure.string :as str] + [deployment.release :as r]) + :task + (if (r/all-good?) + (do + (let [v (r/version!) + ;; commit count + 1 for README update + cc (inc (Integer/parseInt (r/commit-count!))) + rt (r/release-tag (r/commit-count-version v cc))] + (spit "README.md" + (str/replace (slurp "README.md") + (re-pattern (format "(%s)\\.(\\d+)" v)) + (fn [[_ version _]] + (str version "." cc)))) + (shell "git add README.md") + (shell "git commit -m 'Bump version in README'") + (shell "git push")) + (r/release!)) + (println "Unclean!"))}}} From 0fd8791e6c07a56436d9cd388ba3296289be52eb Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:08:53 +0100 Subject: [PATCH 056/143] Add base version --- version.edn | 1 + 1 file changed, 1 insertion(+) create mode 100644 version.edn diff --git a/version.edn b/version.edn new file mode 100644 index 00000000..4ebec580 --- /dev/null +++ b/version.edn @@ -0,0 +1 @@ +"0.4" From 9ad17fadfc97e947fabb68369af1cf94b3b139bc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:09:58 +0100 Subject: [PATCH 057/143] Rename README [skip ci] --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index ef69a46c..b58a0fc4 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.martinklepsch/clj-http-lite "0.4.3"] +[org.martinklepsch/clj-http-lite "0.4.272"] ``` ## Differences from clj-http From 8e232272b3ceeb6b5db1fb15204c06fa165c8ccc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:10:53 +0100 Subject: [PATCH 058/143] Rename README [skip ci] --- Readme.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Readme.md => README.md (100%) diff --git a/Readme.md b/README.md similarity index 100% rename from Readme.md rename to README.md From fbdae2b86541ff6008781daea1c5df3b29d4a10e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:11:38 +0100 Subject: [PATCH 059/143] README [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b58a0fc4..66f5ab8c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.martinklepsch/clj-http-lite "0.4.272"] +[org.clj-commons/clj-http-lite "0.4.273"] ``` ## Differences from clj-http From 6c4ca8be2fc4c395a6af92cdb57ec30f9c770c4d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:11:55 +0100 Subject: [PATCH 060/143] Bump version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66f5ab8c..9973a376 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.273"] +[org.clj-commons/clj-http-lite "0.4.275"] ``` ## Differences from clj-http From 3be9293885cb80ab06c4e6d437e54ddcb618788b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:23:16 +0100 Subject: [PATCH 061/143] Update version in project.clj --- bb.edn | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bb.edn b/bb.edn index 427e24ce..b91ee4bc 100644 --- a/bb.edn +++ b/bb.edn @@ -3,7 +3,13 @@ org.clj-commons/infra {:git/url "https://github.com/clj-commons/infra" :git/sha "a3ebcff4d32c4b84f001f86cdee5c76358d15ea5"}} :tasks - {test:clj {:doc "Run Clojure tests" + {:init (defn replace-version [file version cc] + (spit file + (str/replace (slurp file) + (re-pattern (format "(%s)\\.(\\d+)" version)) + (fn [[_ version _]] + (str version "." cc))))) + test:clj {:doc "Run Clojure tests" :task (clojure "-M:test")} test:bb {:doc "Run babashka tests" :task clj-http.lite.test-runner/-main} @@ -17,11 +23,8 @@ ;; commit count + 1 for README update cc (inc (Integer/parseInt (r/commit-count!))) rt (r/release-tag (r/commit-count-version v cc))] - (spit "README.md" - (str/replace (slurp "README.md") - (re-pattern (format "(%s)\\.(\\d+)" v)) - (fn [[_ version _]] - (str version "." cc)))) + (replace-version "README.md" v cc) + (replace-version "project.clj" v cc) (shell "git add README.md") (shell "git commit -m 'Bump version in README'") (shell "git push")) From 6a20e9fd4def7d3f9265bf3faf9419705ff2b70d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:25:45 +0100 Subject: [PATCH 062/143] Bump version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9973a376..29819520 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.275"] +[org.clj-commons/clj-http-lite "0.4.277"] ``` ## Differences from clj-http From 56d046581b63793ef7633fb0464b7b9349bcdcd0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:25:45 +0100 Subject: [PATCH 063/143] Update version in project.clj --- bb.edn | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bb.edn b/bb.edn index b91ee4bc..2f3fd13e 100644 --- a/bb.edn +++ b/bb.edn @@ -25,7 +25,7 @@ rt (r/release-tag (r/commit-count-version v cc))] (replace-version "README.md" v cc) (replace-version "project.clj" v cc) - (shell "git add README.md") + (shell "git add README.md project.clj") (shell "git commit -m 'Bump version in README'") (shell "git push")) (r/release!)) diff --git a/project.clj b/project.clj index eed500e6..c07b5097 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.3" +(defproject org.martinklepsch/clj-http-lite "0.4.277" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 5b2a1127568ce989030d44f4b9a4ea1849697e75 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:26:11 +0100 Subject: [PATCH 064/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 29819520..8ac8126f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.277"] +[org.clj-commons/clj-http-lite "0.4.278"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index c07b5097..c7af541b 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.277" +(defproject org.martinklepsch/clj-http-lite "0.4.278" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 386f82336bad7f4c6e1e0986fae9c9490e2b9662 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:26:41 +0100 Subject: [PATCH 065/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ac8126f..38e5f47b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.278"] +[org.clj-commons/clj-http-lite "0.4.280"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index c7af541b..db4a721d 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.278" +(defproject org.martinklepsch/clj-http-lite "0.4.280" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From c90487f0a749594bdf2378baa400dd149536b2d4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:29:27 +0100 Subject: [PATCH 066/143] Update version in project.clj --- bb.edn | 14 ++++---------- bb/tasks.clj | 9 +++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 bb/tasks.clj diff --git a/bb.edn b/bb.edn index 2f3fd13e..4fe3eef6 100644 --- a/bb.edn +++ b/bb.edn @@ -3,19 +3,13 @@ org.clj-commons/infra {:git/url "https://github.com/clj-commons/infra" :git/sha "a3ebcff4d32c4b84f001f86cdee5c76358d15ea5"}} :tasks - {:init (defn replace-version [file version cc] - (spit file - (str/replace (slurp file) - (re-pattern (format "(%s)\\.(\\d+)" version)) - (fn [[_ version _]] - (str version "." cc))))) + {:requires ([tasks :as t]) test:clj {:doc "Run Clojure tests" :task (clojure "-M:test")} test:bb {:doc "Run babashka tests" :task clj-http.lite.test-runner/-main} deploy - {:requires ([clojure.string :as str] - [deployment.release :as r]) + {:requires ([deployment.release :as r]) :task (if (r/all-good?) (do @@ -23,8 +17,8 @@ ;; commit count + 1 for README update cc (inc (Integer/parseInt (r/commit-count!))) rt (r/release-tag (r/commit-count-version v cc))] - (replace-version "README.md" v cc) - (replace-version "project.clj" v cc) + (t/replace-version "README.md" v cc) + (t/replace-version "project.clj" v cc) (shell "git add README.md project.clj") (shell "git commit -m 'Bump version in README'") (shell "git push")) diff --git a/bb/tasks.clj b/bb/tasks.clj new file mode 100644 index 00000000..ff39e121 --- /dev/null +++ b/bb/tasks.clj @@ -0,0 +1,9 @@ +(ns tasks + (:require [clojure.string :as str])) + +(defn replace-version [file version cc] + (spit file + (str/replace (slurp file) + (re-pattern (format "(%s)\\.(\\d+)" version)) + (fn [[_ version _]] + (str version "." cc))))) From a39ea0b80f9cd8bd5abea679f05b6020c082cea3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:29:35 +0100 Subject: [PATCH 067/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38e5f47b..54233c8a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.280"] +[org.clj-commons/clj-http-lite "0.4.282"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index db4a721d..a4300de0 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.280" +(defproject org.martinklepsch/clj-http-lite "0.4.282" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From beb34b683830c6f5efb9c4057b2913de44b4c316 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 15:50:42 +0100 Subject: [PATCH 068/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54233c8a..547454d4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.282"] +[org.clj-commons/clj-http-lite "0.4.283"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index a4300de0..c606559f 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.282" +(defproject org.martinklepsch/clj-http-lite "0.4.283" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From ad6008cdfc9b708c85376be554ba8c0db68b61ed Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:01:49 +0100 Subject: [PATCH 069/143] Bump version in README --- README.md | 2 +- project.clj | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 547454d4..eb9b4230 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.283"] +[org.clj-commons/clj-http-lite "0.4.284"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index c606559f..3a628858 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.martinklepsch/clj-http-lite "0.4.283" +(defproject org.clj-commons/clj-http-lite "0.4.284" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" @@ -19,4 +19,8 @@ :all (constantly true) :unit #(not (:integration %)) :integration :integration} - :checksum-deps true) + :checksum-deps true + :deploy-repositories [["clojars" {:url "https://clojars.org/repo" + :username :env/clojars_user + :password :env/clojars_pass + :sign-releases false}]]) From d91485f8a9ffa427cbfa14d72b1ac3c81a1688e4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:05:39 +0100 Subject: [PATCH 070/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb9b4230..4c352a89 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.284"] +[org.clj-commons/clj-http-lite "0.4.372"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 3a628858..d62daa37 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.284" +(defproject org.clj-commons/clj-http-lite "0.4.372" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 23e59e5a56f6cb1bf8df15a2365bd696468c17a2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:06:21 +0100 Subject: [PATCH 071/143] Bump version in README --- README.md | 2 +- bb.edn | 2 +- bb/tasks.clj | 9 ++++++++- project.clj | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4c352a89..873f320d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.372"] +[org.clj-commons/clj-http-lite "0.4.373"] ``` ## Differences from clj-http diff --git a/bb.edn b/bb.edn index 4fe3eef6..026f0e02 100644 --- a/bb.edn +++ b/bb.edn @@ -15,7 +15,7 @@ (do (let [v (r/version!) ;; commit count + 1 for README update - cc (inc (Integer/parseInt (r/commit-count!))) + cc (inc (Integer/parseInt (t/git-count-revs))) rt (r/release-tag (r/commit-count-version v cc))] (t/replace-version "README.md" v cc) (t/replace-version "project.clj" v cc) diff --git a/bb/tasks.clj b/bb/tasks.clj index ff39e121..b096d25a 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -1,9 +1,16 @@ (ns tasks - (:require [clojure.string :as str])) + (:require [babashka.tasks :refer [shell]] + [clojure.string :as str])) (defn replace-version [file version cc] + (prn version cc) (spit file (str/replace (slurp file) (re-pattern (format "(%s)\\.(\\d+)" version)) (fn [[_ version _]] (str version "." cc))))) + +(defn git-count-revs [] + (-> (shell {:out :string} "git rev-list HEAD --count") + :out + str/trim)) diff --git a/project.clj b/project.clj index d62daa37..c1311644 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.372" +(defproject org.clj-commons/clj-http-lite "0.4.373" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 39046a5022def82aa05784e6f69999f854e62c8b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:29:34 +0100 Subject: [PATCH 072/143] Build stuff --- bb.edn | 22 +++------------------- bb/tasks.clj | 16 ++++++++++++---- build.clj | 5 +++-- build_shared.clj | 12 ++++++++++++ 4 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 build_shared.clj diff --git a/bb.edn b/bb.edn index 026f0e02..5a1ef286 100644 --- a/bb.edn +++ b/bb.edn @@ -1,7 +1,5 @@ -{:paths ["bb"] - :deps {org.clj-commons/clj-http-lite {:local/root "."} - org.clj-commons/infra {:git/url "https://github.com/clj-commons/infra" - :git/sha "a3ebcff4d32c4b84f001f86cdee5c76358d15ea5"}} +{:paths ["." "bb"] + :deps {org.clj-commons/clj-http-lite {:local/root "."}} :tasks {:requires ([tasks :as t]) test:clj {:doc "Run Clojure tests" @@ -9,18 +7,4 @@ test:bb {:doc "Run babashka tests" :task clj-http.lite.test-runner/-main} deploy - {:requires ([deployment.release :as r]) - :task - (if (r/all-good?) - (do - (let [v (r/version!) - ;; commit count + 1 for README update - cc (inc (Integer/parseInt (t/git-count-revs))) - rt (r/release-tag (r/commit-count-version v cc))] - (t/replace-version "README.md" v cc) - (t/replace-version "project.clj" v cc) - (shell "git add README.md project.clj") - (shell "git commit -m 'Bump version in README'") - (shell "git push")) - (r/release!)) - (println "Unclean!"))}}} + {:task (t/deploy)}}} diff --git a/bb/tasks.clj b/bb/tasks.clj index b096d25a..7cd6b8f6 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -1,5 +1,6 @@ (ns tasks (:require [babashka.tasks :refer [shell]] + [build-shared :as shared] [clojure.string :as str])) (defn replace-version [file version cc] @@ -10,7 +11,14 @@ (fn [[_ version _]] (str version "." cc))))) -(defn git-count-revs [] - (-> (shell {:out :string} "git rev-list HEAD --count") - :out - str/trim)) +(defn deploy [] + (let [;; commit count + 1 for README update + cc (inc (Integer/parseInt (shared/git-count-revs))) + tag (str "Release-" shared/version)] + (replace-version "README.md" shared/base-version cc) + (replace-version "project.clj" shared/base-version cc) + (shell "git add README.md project.clj") + (shell "git commit -m 'Bump version in README'") + (shell "git push") + (shell "git tag" tag) + (shell "git push origin" tag))) diff --git a/build.clj b/build.clj index 59dbfef9..c3d6cb92 100644 --- a/build.clj +++ b/build.clj @@ -1,9 +1,10 @@ (ns build - (:require [clojure.string :as str] + (:require [build-shared :as shared] + [clojure.string :as str] [clojure.tools.build.api :as b])) (def lib 'org.clj-commons/clj-http-lite) -(def version (format "0.4.%s" (b/git-count-revs nil))) +(def version shared/version) (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) diff --git a/build_shared.clj b/build_shared.clj new file mode 100644 index 00000000..f439f676 --- /dev/null +++ b/build_shared.clj @@ -0,0 +1,12 @@ +(ns build-shared + (:require [clojure.edn :as edn] + [clojure.java.shell :refer [sh]] + [clojure.string :as str])) + +(defn git-count-revs [] + (-> (apply sh (str/split "git rev-list HEAD --count" #" ")) + :out + str/trim)) + +(def base-version (edn/read-string (slurp "version.edn"))) +(def version (str base-version "." (git-count-revs))) From 031a0cb05ebae77fb14850e87dc82baea89fa2d4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:29:38 +0100 Subject: [PATCH 073/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 873f320d..6a5c3c2c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.373"] +[org.clj-commons/clj-http-lite "0.4.375"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index c1311644..54e80c92 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.373" +(defproject org.clj-commons/clj-http-lite "0.4.375" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From e5011ad0786f62bf5e7fd0194e7a5c9bb41c727d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:35:02 +0100 Subject: [PATCH 074/143] fetch depth 0 --- .github/workflows/ci.yml | 2 ++ bb.edn | 4 ++-- bb/tasks.clj | 5 ++--- build_shared.clj | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 659a2d81..7dc6173c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,8 @@ jobs: - bb-test steps: - name: Checkout + with: + fetch-depth: 0 uses: actions/checkout@v2-beta - name: Install clojure tools uses: DeLaGuardo/setup-clojure@3.5 diff --git a/bb.edn b/bb.edn index 5a1ef286..cc84dd47 100644 --- a/bb.edn +++ b/bb.edn @@ -6,5 +6,5 @@ :task (clojure "-M:test")} test:bb {:doc "Run babashka tests" :task clj-http.lite.test-runner/-main} - deploy - {:task (t/deploy)}}} + publish + {:task (t/publish)}}} diff --git a/bb/tasks.clj b/bb/tasks.clj index 7cd6b8f6..1a1343b4 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -4,16 +4,15 @@ [clojure.string :as str])) (defn replace-version [file version cc] - (prn version cc) (spit file (str/replace (slurp file) (re-pattern (format "(%s)\\.(\\d+)" version)) (fn [[_ version _]] (str version "." cc))))) -(defn deploy [] +(defn publish [] (let [;; commit count + 1 for README update - cc (inc (Integer/parseInt (shared/git-count-revs))) + cc (inc (shared/git-count-revs)) tag (str "Release-" shared/version)] (replace-version "README.md" shared/base-version cc) (replace-version "project.clj" shared/base-version cc) diff --git a/build_shared.clj b/build_shared.clj index f439f676..24fc91e3 100644 --- a/build_shared.clj +++ b/build_shared.clj @@ -6,7 +6,8 @@ (defn git-count-revs [] (-> (apply sh (str/split "git rev-list HEAD --count" #" ")) :out - str/trim)) + str/trim + Integer/parseInt)) (def base-version (edn/read-string (slurp "version.edn"))) (def version (str base-version "." (git-count-revs))) From dfbe3bfdca1a285493af521ee55f015efc15c198 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:35:44 +0100 Subject: [PATCH 075/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a5c3c2c..820148fe 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.375"] +[org.clj-commons/clj-http-lite "0.4.377"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 54e80c92..436637c3 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.375" +(defproject org.clj-commons/clj-http-lite "0.4.377" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 2c2d5184bb4ffc009c04eb8730549afcaf59e888 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:42:51 +0100 Subject: [PATCH 076/143] Fix future version --- bb/tasks.clj | 2 +- build.clj | 2 +- build_shared.clj | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bb/tasks.clj b/bb/tasks.clj index 1a1343b4..54008fc2 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -13,7 +13,7 @@ (defn publish [] (let [;; commit count + 1 for README update cc (inc (shared/git-count-revs)) - tag (str "Release-" shared/version)] + tag (str "Release-" (shared/version cc))] (replace-version "README.md" shared/base-version cc) (replace-version "project.clj" shared/base-version cc) (shell "git add README.md project.clj") diff --git a/build.clj b/build.clj index c3d6cb92..5a68cccb 100644 --- a/build.clj +++ b/build.clj @@ -4,7 +4,7 @@ [clojure.tools.build.api :as b])) (def lib 'org.clj-commons/clj-http-lite) -(def version shared/version) +(def version (shared/version (shared/git-count-revs))) (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) diff --git a/build_shared.clj b/build_shared.clj index 24fc91e3..c433599e 100644 --- a/build_shared.clj +++ b/build_shared.clj @@ -10,4 +10,6 @@ Integer/parseInt)) (def base-version (edn/read-string (slurp "version.edn"))) -(def version (str base-version "." (git-count-revs))) + +(defn version [revs] + (str base-version "." revs)) From c57a75866a3ea862d21db637b2ecea1001b46c48 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:42:54 +0100 Subject: [PATCH 077/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 820148fe..e0043742 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.377"] +[org.clj-commons/clj-http-lite "0.4.379"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 436637c3..c380da81 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.377" +(defproject org.clj-commons/clj-http-lite "0.4.379" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From a0d69e0af85a2e9968173347df8d5518e2d0190c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:46:52 +0100 Subject: [PATCH 078/143] Merge options --- build.clj | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build.clj b/build.clj index 5a68cccb..b008088d 100644 --- a/build.clj +++ b/build.clj @@ -12,12 +12,13 @@ (defn clean [_] (b/delete {:path "target"})) -(defn jar [_] - (b/write-pom {:class-dir class-dir - :lib lib - :version version - :basis basis - :src-dirs ["src"]}) +(defn jar [opts] + (b/write-pom (merge {:class-dir class-dir + :lib lib + :version version + :basis basis + :src-dirs ["src"]} + opts)) (b/copy-dir {:src-dirs ["src" "resources"] :target-dir class-dir}) (b/jar {:class-dir class-dir From 89e4ea90cdd4179cc362af1e22d61a640e093f6a Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:48:08 +0100 Subject: [PATCH 079/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e0043742..544f7bd2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.379"] +[org.clj-commons/clj-http-lite "0.4.381"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index c380da81..91bd1d50 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.379" +(defproject org.clj-commons/clj-http-lite "0.4.381" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 72df0aa9ac89b9e73c81c4e3035b8e30ab3d5801 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:54:58 +0100 Subject: [PATCH 080/143] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 544f7bd2..1257271f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.martinklepsch/clj-http-lite)](https://cljdoc.xyz/d/org.martinklepsch/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) +# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.clj-commons/clj-http-lite)](https://cljdoc.xyz/d/org.clj-commons/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. @@ -8,7 +8,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) ## Installation -`clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.martinklepsch/clj-http-lite): +`clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.clj-commons/clj-http-lite): ```clojure [org.clj-commons/clj-http-lite "0.4.381"] From 0126a3fccc8e374ef6072e3e56bc21bbc0e37ffc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:59:21 +0100 Subject: [PATCH 081/143] set env --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7dc6173c..c9cf8e6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,4 +50,7 @@ jobs: # Install just one or all simultaneously cli: 1.10.3.1029 # Clojure CLI based on tools.deps - name: Deploy + env: + CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }} + CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }} run: clojure -T:build maybe-deploy From f8e86fc7e904aee75a5e3d8b0662a4fe010059f6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 16:59:25 +0100 Subject: [PATCH 082/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1257271f..d72a90ef 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.clj-commons/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.381"] +[org.clj-commons/clj-http-lite "0.4.384"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 91bd1d50..fe20a80d 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.381" +(defproject org.clj-commons/clj-http-lite "0.4.384" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 7f3d064874ede6410e641f635dbe05b921ca9ae5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:03:49 +0100 Subject: [PATCH 083/143] README --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d72a90ef..0254f698 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,9 @@ are sugar over this `clj-http.lite.client/request` function. ## Development -To run the tests: +### Tests + +To run the tests for the JVM: $ lein deps $ lein test @@ -225,6 +227,15 @@ To run the tests: Run tests against 1.2.1, 1.3, 1.4 and 1.5 $ lein all do clean, test :all +To run the tests for babashka: + + $ bb test:bb + +### Release + +To release a new version, run `bb publish` which will push a new tag. CI will +take care of the rest. + ## License Released under the MIT License: From 32b867b198cd3e762392b9ea49d69f3a14d0bc7c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:08:20 +0100 Subject: [PATCH 084/143] CHANGELOGS [skip ci] --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72e10193..66e13b5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ### Unreleased +### 0.4.384 + - Support self-signed certificates via `:insecure? true` option -- Remove dependency on Slingshot +- Remove dependency on slingshot ### 0.4.3 From 83193c8908318878fb2cdfa5c7e13b52b9a12cea Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:09:30 +0100 Subject: [PATCH 085/143] CHANGELOGS [skip ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66e13b5b..70a688eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Support self-signed certificates via `:insecure? true` option - Remove dependency on slingshot +- Move to `org.clj-commons` group ### 0.4.3 From 9d61a356ce382a9ad01388349fb132789382c6dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:10:13 +0100 Subject: [PATCH 086/143] CHANGELOGS [skip ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a688eb..498f4d7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Support self-signed certificates via `:insecure? true` option - Remove dependency on slingshot - Move to `org.clj-commons` group +- Add compatibility with [babashka](https://babashka.org/) ### 0.4.3 From 6f750846e0f083e2d7c32fd1e023572523ddb008 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:33:38 +0100 Subject: [PATCH 087/143] Update SCM info --- build.clj | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/build.clj b/build.clj index b008088d..7f36a6b9 100644 --- a/build.clj +++ b/build.clj @@ -8,17 +8,22 @@ (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) +(def github-repo "https://github.com/clj-commons/clj-http-lite") (defn clean [_] (b/delete {:path "target"})) (defn jar [opts] - (b/write-pom (merge {:class-dir class-dir - :lib lib - :version version - :basis basis - :src-dirs ["src"]} - opts)) + (let [opts (merge {:class-dir class-dir + :lib lib + :version version + :basis basis + :src-dirs ["src"]} + opts) + opts (assoc opts :scm + {:url "https://github.com/clj-commons/clj-http-lite" + :tag (:version opts)})] + (b/write-pom opts)) (b/copy-dir {:src-dirs ["src" "resources"] :target-dir class-dir}) (b/jar {:class-dir class-dir From b71361b9ddd69eea779615f15542d329d38776a2 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:33:42 +0100 Subject: [PATCH 088/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0254f698..08bb40e1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.clj-commons/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.384"] +[org.clj-commons/clj-http-lite "0.4.390"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index fe20a80d..827aad71 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.384" +(defproject org.clj-commons/clj-http-lite "0.4.390" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From ff68fe4c881a1c0257f3634dd601282286b1e28d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:45:16 +0100 Subject: [PATCH 089/143] tag fix --- build.clj | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build.clj b/build.clj index 7f36a6b9..e6f22bf1 100644 --- a/build.clj +++ b/build.clj @@ -21,8 +21,8 @@ :src-dirs ["src"]} opts) opts (assoc opts :scm - {:url "https://github.com/clj-commons/clj-http-lite" - :tag (:version opts)})] + (cond-> {:url "https://github.com/clj-commons/clj-http-lite"} + (:tag opts) (assoc :tag (:tag opts))))] (b/write-pom opts)) (b/copy-dir {:src-dirs ["src" "resources"] :target-dir class-dir}) @@ -55,7 +55,9 @@ (do (println "Releasing to clojars...") (-> opts - (assoc :lib lib :version (extract-version tag)) + (assoc :lib lib + :version (extract-version tag) + :tag tag) (deploy))) (do (println "Tag is not a release tag, skipping deploy") From 6b53000df55ac05c4ff8e5047a5323fc08a52e8b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Thu, 18 Nov 2021 17:45:20 +0100 Subject: [PATCH 090/143] Bump version in README --- README.md | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08bb40e1..c699924c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) `clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.clj-commons/clj-http-lite): ```clojure -[org.clj-commons/clj-http-lite "0.4.390"] +[org.clj-commons/clj-http-lite "0.4.392"] ``` ## Differences from clj-http diff --git a/project.clj b/project.clj index 827aad71..b19e4b43 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject org.clj-commons/clj-http-lite "0.4.390" +(defproject org.clj-commons/clj-http-lite "0.4.392" :description "A Clojure HTTP library similar to clj-http, but more lightweight." :url "https://github.com/martinklepsch/clj-http-lite/" :license {:name "MIT" From 0f0ea8737e50b5c9210b36b83c11869dcec7f67e Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 1 Jun 2022 03:51:57 -0400 Subject: [PATCH 091/143] docs: Add babashka compatible badge to README (#19) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c699924c..84a3d92b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.clj-commons/clj-http-lite)](https://cljdoc.xyz/d/org.clj-commons/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) +# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.clj-commons/clj-http-lite)](https://cljdoc.xyz/d/org.clj-commons/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. From 1228fc868fa58d8d0d597e2e82bb7e11a9633af1 Mon Sep 17 00:00:00 2001 From: Andreas Steffan Date: Wed, 1 Jun 2022 10:02:33 +0200 Subject: [PATCH 092/143] Implemented oauth-header wrap (#7) * feat: Implemented oauth-header wrap --- CHANGELOG.md | 1 + src/clj_http/lite/client.clj | 11 ++++++++++- test/clj_http/test/client.clj | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 498f4d7d..dcd37fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Remove dependency on slingshot - Move to `org.clj-commons` group - Add compatibility with [babashka](https://babashka.org/) +- **Feature:** Support for`:oauth-token` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/7)) ### 0.4.3 diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index 57637d61..b9152248 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -222,6 +222,14 @@ nil (throw e)))))) +(defn wrap-oauth [client] + (fn [{:keys [oauth-token] :as req}] + (if oauth-token + (client (-> req (dissoc :oauth-token) + (assoc-in [:headers "Authorization"] + (str "Bearer " oauth-token)))) + (client req)))) + (defn wrap-request "Returns a battaries-included HTTP request function coresponding to the given core client. See client/client." @@ -242,7 +250,8 @@ wrap-form-params wrap-method wrap-links - wrap-unknown-host)) + wrap-unknown-host + wrap-oauth)) (def #^{:doc "Executes the HTTP request corresponding to the given map and returns diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index f81ebcf7..064b8934 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -123,6 +123,15 @@ (is-passed client/wrap-accept {:uri "/foo"})) +(deftest apply-on-oauth + (is-applied client/wrap-oauth + {:oauth-token "sample-token"} + {:headers {"Authorization" "Bearer sample-token"}})) + +(deftest pass-on-no-oauth + (is-passed client/wrap-oauth + {:uri "/foo"})) + (deftest apply-on-accept-encoding (is-applied client/wrap-accept-encoding {:accept-encoding [:identity :gzip]} From 1e61d0bfd9a560189c4ba56cce66a4723387a9e3 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sat, 13 Aug 2022 04:52:13 -0400 Subject: [PATCH 093/143] tests: move fully to deps.edn (#22) * tests: move fully to deps.edn No longer using lein at all. Bumped all deps to current releases except for ring-jetty-adapter. It is used for testing only, and bumping will require code changes. Can address as a separate issue later, if we like. Turfed bb test:clj task. I did not want to wrap clojure cli test running with bb as part of this work Removed special instructions in README about skipping integration tests, they run very fast, so not generally worth skipping. Dropped testing of Clojure 1.7, Clojure tools cli min version seems to be 1.8, and we planned to to this anyway as part of #21. Added new bb tasks to replace lein's versions - clean - deps - brings down all deps Closes #20 * bump ci bb to latest, cleanup unused requires --- .github/workflows/ci.yml | 13 ++++++------- README.md | 20 +++++++++++--------- bb.edn | 16 +++++++++++----- bb/tasks.clj | 16 +++++++++++++++- deps.edn | 23 ++++++++++++++--------- project.clj | 26 -------------------------- 6 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 project.clj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9cf8e6a..faee2bf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - clojure-version: ["1.7", "1.8", "1.9", "1.10"] + clojure-version: ["1.8", "1.9", "1.10"] java-version: ["8", "11", "16"] steps: - name: Prepare java @@ -15,23 +15,22 @@ jobs: distribution: "adopt" java-version: ${{ matrix.java-version }} - name: Setup Clojure - uses: DeLaGuardo/setup-clojure@3.4 + uses: DeLaGuardo/setup-clojure@9.4 with: - lein: 2.9.4 + cli: 'latest' - name: Checkout uses: actions/checkout@v2-beta - name: Run tests - run: lein with-profile -user,-dev,+test,+${{ matrix.clojure-version }} do clean, test + run: clojure -M:${{ matrix.clojure-version }}:test bb-test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2-beta - name: Setup Babashka - uses: turtlequeue/setup-babashka@v1.3.0 + uses: DeLaGuardo/setup-clojure@9.4 with: - babashka-version: 0.6.4 - + bb: 'latest' - name: tests run: bb test:bb deploy: diff --git a/README.md b/README.md index 84a3d92b..33fdb8e4 100644 --- a/README.md +++ b/README.md @@ -214,20 +214,22 @@ are sugar over this `clj-http.lite.client/request` function. ## Development -### Tests +### Clojure JVM Tests -To run the tests for the JVM: +To run tests for the JVM: - $ lein deps - $ lein test + $ bb clean + $ bb deps - Run all tests (including integration): - $ lein test :all + Run all Clojure tests against minimum supported version of Clojure (1.8) + $ clojure -M:test - Run tests against 1.2.1, 1.3, 1.4 and 1.5 - $ lein all do clean, test :all + Run Clojure against a specific Clojure version, for example 1.11 + $ clojure -M:1.11:test -To run the tests for babashka: +### Babashka Tests + +To run a small suite of sanity tests for babashka (found under ./bb]): $ bb test:bb diff --git a/bb.edn b/bb.edn index cc84dd47..9e15ceb6 100644 --- a/bb.edn +++ b/bb.edn @@ -2,9 +2,15 @@ :deps {org.clj-commons/clj-http-lite {:local/root "."}} :tasks {:requires ([tasks :as t]) - test:clj {:doc "Run Clojure tests" - :task (clojure "-M:test")} - test:bb {:doc "Run babashka tests" - :task clj-http.lite.test-runner/-main} + deps + {:doc "Bring down all the clojure deps" + :task (t/deps)} + clean + {:doc "Delete any work dirs" + :task (clojure "-T:build clean")} + test:bb + {:doc "Run babashka tests" + :task clj-http.lite.test-runner/-main} publish - {:task (t/publish)}}} + {:doc "Trigger a release to clojars" + :task (t/publish)}}} diff --git a/bb/tasks.clj b/bb/tasks.clj index 54008fc2..70a931ef 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -1,8 +1,22 @@ (ns tasks - (:require [babashka.tasks :refer [shell]] + (:require [babashka.tasks :refer [shell clojure]] [build-shared :as shared] + [clojure.edn :as edn] [clojure.string :as str])) +(defn deps [] + (let [aliases (->> "deps.edn" + slurp + edn/read-string + :aliases + keys)] + ;; one at a time because aliases with :replace-deps or override-deps will... well... you know. + (println "Bring down default deps") + (clojure "-P") + (doseq [a aliases] + (println "Bring down deps for alias" a) + (clojure "-P" (str "-M" a))))) + (defn replace-version [file version cc] (spit file (str/replace (slurp file) diff --git a/deps.edn b/deps.edn index 96f0cb2c..8c107504 100644 --- a/deps.edn +++ b/deps.edn @@ -1,19 +1,24 @@ {:paths ["src"] :deps {org.clojure/clojure {:mvn/version "1.8.0"}} :aliases - {:build - {:deps {io.github.clojure/tools.build {:git/tag "v0.6.6" :git/sha "4d41c26"} + {:1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} + :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} + :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} + :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.1"}}} + :build + {:deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} slipset/deps-deploy {:mvn/version "0.2.0"}} :ns-default build} :test {:extra-paths ["test" "test-resources"] :extra-deps {io.github.cognitect-labs/test-runner - {:git/tag "v0.5.0" :git/sha "b3fd0d2"} + {:git/tag "v0.5.1" :git/sha "dfb30dd"} ring/ring-jetty-adapter {:mvn/version "1.3.2"} - ch.qos.logback/logback-classic {:mvn/version "1.2.3" + ch.qos.logback/logback-classic {:mvn/version "1.2.11" :exclusions [org.slf4j/slf4j-api]} - org.slf4j/jcl-over-slf4j {:mvn/version "1.7.26"} - org.slf4j/jul-to-slf4j {:mvn/version "1.7.26"} - org.slf4j/log4j-over-slf4j {:mvn/version "1.7.26"}} - :main-opts ["-m" "cognitect.test-runner"] - :exec-fn cognitect.test-runner.api/test}}} + org.slf4j/jcl-over-slf4j {:mvn/version "1.7.36"} + org.slf4j/jul-to-slf4j {:mvn/version "1.7.36"} + org.slf4j/log4j-over-slf4j {:mvn/version "1.7.36"}} + :main-opts ["-m" "cognitect.test-runner" + ;; our test namespaces do not always end in -test, hence the override: + "--namespace-regex" "clj-http\\.test\\..*"]}}} diff --git a/project.clj b/project.clj deleted file mode 100644 index b19e4b43..00000000 --- a/project.clj +++ /dev/null @@ -1,26 +0,0 @@ -(defproject org.clj-commons/clj-http-lite "0.4.392" - :description "A Clojure HTTP library similar to clj-http, but more lightweight." - :url "https://github.com/martinklepsch/clj-http-lite/" - :license {:name "MIT" - :url "http://www.opensource.org/licenses/mit-license.php"} - :dependencies [[org.clojure/clojure "1.8.0"]] - :profiles {:test {:dependencies [[ring/ring-jetty-adapter "1.3.2"] - [ch.qos.logback/logback-classic "1.2.3" - :exclusions [org.slf4j/slf4j-api]] - [org.slf4j/jcl-over-slf4j "1.7.26"] - [org.slf4j/jul-to-slf4j "1.7.26"] - [org.slf4j/log4j-over-slf4j "1.7.26"]] - :resource-paths ["test-resources"]} - :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} - :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} - :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]} - :1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}} - :test-selectors {:default (constantly true) - :all (constantly true) - :unit #(not (:integration %)) - :integration :integration} - :checksum-deps true - :deploy-repositories [["clojars" {:url "https://clojars.org/repo" - :username :env/clojars_user - :password :env/clojars_pass - :sign-releases false}]]) From 4da1cc23865cd07b507c6c6eaf5ecfecabe56b65 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sat, 13 Aug 2022 11:29:28 -0400 Subject: [PATCH 094/143] Lee volunteers to be on maintainers team (#23) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5cfcee2c..1dc6f1cf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -@borkdude @martinklepsch @slipset +@borkdude @lread @martinklepsch @slipset From 09b4e0e460fa125f6ee722f2bf70336549356633 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sat, 13 Aug 2022 13:10:48 -0400 Subject: [PATCH 095/143] ci: add windows to matrix, freshen config (#24) Add Windows to test matrix for jvm and bb tests No longer failing fast on first matrix job failure Bump GitHub actions Employ deps cache Switch to temurin for Java vendor Report which tools versions were installed Download deps prior to running main clj jvm action Closes #21 --- .github/workflows/ci.yml | 132 +++++++++++++++++++++++++++++++++------ 1 file changed, 114 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faee2bf1..469c1999 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,51 +3,147 @@ on: [push, pull_request] jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }}-latest strategy: + fail-fast: false matrix: - clojure-version: ["1.8", "1.9", "1.10"] - java-version: ["8", "11", "16"] + os: ["ubuntu", "windows"] + clojure-version: ["1.8", "1.9", "1.10", "1.11"] + java-version: ["8", "11", "17"] + + name: ${{ matrix.os }} clj-${{ matrix.clojure-version }} jdk${{ matrix.java-version }} + steps: - - name: Prepare java - uses: actions/setup-java@v2 + - name: Checkout + uses: actions/checkout@v3.0.2 + + - name: Clojure deps cache + uses: actions/cache@v3 with: - distribution: "adopt" + path: | + ~/.m2/repository + ~/.deps.clj + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} + restore-keys: cljdeps- + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: "temurin" java-version: ${{ matrix.java-version }} - - name: Setup Clojure + + - name: Setup Clojure Tooling uses: DeLaGuardo/setup-clojure@9.4 with: + bb: 'latest' cli: 'latest' - - name: Checkout - uses: actions/checkout@v2-beta + + - name: Tools versions + run: | + echo "bb --version" + bb --version + echo "clojure --version" + clojure --version + echo "java -version" + java -version + + - name: Bring down deps + run: bb deps + - name: Run tests run: clojure -M:${{ matrix.clojure-version }}:test + bb-test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: ["ubuntu", "windows"] + + name: ${{ matrix.os }} bb + steps: - name: Checkout - uses: actions/checkout@v2-beta - - name: Setup Babashka + uses: actions/checkout@v3.0.2 + + - name: Clojure deps cache + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository + ~/.deps.clj + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} + restore-keys: cljdeps- + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: "temurin" + java-version: '17' + + - name: Setup Clojure Tooling uses: DeLaGuardo/setup-clojure@9.4 with: bb: 'latest' - - name: tests + + - name: Tools versions + run: | + echo "bb --version" + bb --version + echo "java -version" + java -version + + - name: Run tests run: bb test:bb + deploy: runs-on: ubuntu-latest needs: - test - bb-test + steps: - name: Checkout + uses: actions/checkout@v3.0.2 with: fetch-depth: 0 - uses: actions/checkout@v2-beta - - name: Install clojure tools - uses: DeLaGuardo/setup-clojure@3.5 + + - name: Clojure deps cache + uses: actions/cache@v3 with: - # Install just one or all simultaneously - cli: 1.10.3.1029 # Clojure CLI based on tools.deps + path: | + ~/.m2/repository + ~/.deps.clj + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} + restore-keys: cljdeps- + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + - name: Setup Clojure Tooling + uses: DeLaGuardo/setup-clojure@9.4 + with: + bb: 'latest' + cli: 'latest' + + - name: Tools versions + run: | + echo "bb --version" + bb --version + echo "clojure --version" + clojure --version + echo "java -version" + java -version + + - name: Bring down deps + run: bb deps + - name: Deploy env: CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }} From da0e63438f72ff1b9219696a9ae661161ee2a7a7 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sun, 14 Aug 2022 10:41:20 -0400 Subject: [PATCH 096/143] Body encoding now applied and always defaults to UTF-8 (#25) * Body encoding now always defaults to UTF-8 Was previously always encoding to system default character encoding, which is UTF-8 unless on Windows then it is windows-1252. Now: - encoding body to requested body encoding - and defaulting to UTF-8 if no body encoding requested Also: - Added extended characters to http bodies in tests to exercise body encoding/decoding - Verified :auto body decoding with an extra test Note that :auto body decoding might not be entirely correct. It will only look at content-type charset if content-type starts with "text/". Diagnosing/fixing this is out of scope for this PR. Fixes #18 --- CHANGELOG.md | 4 ++++ src/clj_http/lite/client.clj | 16 +++++++------- test/clj_http/test/client.clj | 39 +++++++++++++++++++++-------------- test/clj_http/test/core.clj | 2 +- 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd37fc2..ad8bbfd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ### Unreleased +- If specified, request's body encoding is now applied, else defaults to UTF-8 ([#18](https://github.com/clj-commons/clj-http-lite/issues/18)) ([@lread](https://github.com/lread)) +- Quality + - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) + ### 0.4.384 - Support self-signed certificates via `:insecure? true` option diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index b9152248..df0f7fb1 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -5,7 +5,8 @@ [clj-http.lite.util :as util] [clojure.java.io :as io] [clojure.string :as str]) - (:import (java.net UnknownHostException)) + (:import (java.net UnknownHostException) + (java.nio.charset Charset)) (:refer-clojure :exclude (get update))) (set! *warn-on-reflection* true) @@ -106,12 +107,13 @@ (fn [{:keys [body body-encoding _length] :as req}] (if body (cond - (string? body) - (client (-> req (assoc :body (.getBytes ^String body) - :character-encoding (or body-encoding - "UTF-8")))) - :else - (client req)) + (string? body) + (let [encoding-name (or body-encoding "UTF-8") + charset (Charset/forName encoding-name)] + (client (-> req (assoc :body (.getBytes ^String body charset) + :character-encoding encoding-name)))) + :else + (client req)) (client req)))) (defn content-type-value [type] diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index 064b8934..1d0a7ae9 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -93,21 +93,21 @@ (let [client (fn [req] (is (= "gzip, deflate" (get-in req [:headers "Accept-Encoding"]))) - {:body (util/gzip (util/utf8-bytes "foofoofoo")) + {:body (util/gzip (util/utf8-bytes "foofoofooƒ⊙⊙")) :headers {"Content-Encoding" "gzip"}}) c-client (client/wrap-decompression client) resp (c-client {})] - (is (= "foofoofoo" (util/utf8-string (:body resp)))))) + (is (= "foofoofooƒ⊙⊙" (util/utf8-string (:body resp)))))) (deftest apply-on-deflated (let [client (fn [req] (is (= "gzip, deflate" (get-in req [:headers "Accept-Encoding"]))) - {:body (util/deflate (util/utf8-bytes "barbarbar")) + {:body (util/deflate (util/utf8-bytes "barbarbar⒝⒜⒭")) :headers {"Content-Encoding" "deflate"}}) c-client (client/wrap-decompression client) resp (c-client {})] - (is (= "barbarbar" (util/utf8-string (:body resp)))))) + (is (= "barbarbar⒝⒜⒭" (util/utf8-string (:body resp)))))) (deftest pass-on-non-compressed (let [c-client (client/wrap-decompression (fn [req] {:body "foo"})) @@ -141,11 +141,18 @@ (is-passed client/wrap-accept-encoding {:uri "/foo"})) -(deftest apply-on-output-coercion - (let [client (fn [req] {:body (util/utf8-bytes "foo")}) +(deftest apply-on-utf8-output-coercion + (let [client (fn [req] {:body (util/utf8-bytes "fooⓕⓞⓞ")}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo"})] - (is (= "foo" (:body resp))))) + (is (= "fooⓕⓞⓞ" (:body resp))))) + +(deftest apply-on-other-output-coercion + (let [client (fn [req] {:body (.getBytes "sõme ßÒññÝ chÀråcters" "windows-1252") + :headers {"content-type" "text/foo;charset=windows-1252"}}) + o-client (client/wrap-output-coercion client) + resp (o-client {:uri "/foo" :as :auto})] + (is (= "sõme ßÒññÝ chÀråcters" (:body resp))))) (deftest pass-on-no-output-coercion (let [client (fn [req] {:body nil}) @@ -158,15 +165,15 @@ (is (= :thebytes (:body resp))))) (deftest apply-on-input-coercion - (let [i-client (client/wrap-input-coercion identity) - resp (i-client {:body "foo"}) - resp2 (i-client {:body "foo2" :body-encoding "ASCII"}) - data (slurp (:body resp)) - data2 (slurp (:body resp2))] - (is (= "UTF-8" (:character-encoding resp))) - (is (= "foo" data)) - (is (= "ASCII" (:character-encoding resp2))) - (is (= "foo2" data2)))) + (let [i-client (client/wrap-input-coercion identity)] + (doseq [[in-body encoding expected-encoding] [["μτƒ8 нαs мαηλ ςнαяαςτεяs ൠ" nil "UTF-8"] + ["μτƒ8 нαs мαηλ ςнαяαςτεяs ൠ" "UTF-8" "UTF-8"] + ["plain text" "ASCII" "ASCII"] + ["sõme ßÒññÝ chÀråcters" "windows-1252" "windows-1252"]]] + (let [resp (i-client {:body in-body :body-encoding encoding}) + decoded-body (slurp (:body resp) :encoding expected-encoding)] + (is (= expected-encoding (:character-encoding resp)) "character encoding") + (is (= in-body decoded-body) "body"))))) (deftest pass-on-no-input-coercion (is-passed client/wrap-input-coercion diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 3c81b9e8..daa4da3f 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -165,7 +165,7 @@ (deftest ^{:integration true} t-save-request-obj (let [resp (request {:request-method :post :uri "/post" - :body (.getBytes "foo bar") + :body (.getBytes "foo bar" "UTF-8") :save-request? true})] (is (= 200 (:status resp))) (is (= {:scheme :http From e7ef9239eb1e60671f623ae30b4a80bfc81713cc Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sun, 14 Aug 2022 17:03:52 -0400 Subject: [PATCH 097/143] tests: bump ring-jetty-adapter (#29) Closes #27 --- deps.edn | 2 +- test/clj_http/test/core.clj | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/deps.edn b/deps.edn index 8c107504..a6e23a27 100644 --- a/deps.edn +++ b/deps.edn @@ -13,7 +13,7 @@ {:extra-paths ["test" "test-resources"] :extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"} - ring/ring-jetty-adapter {:mvn/version "1.3.2"} + ring/ring-jetty-adapter {:mvn/version "1.9.5"} ch.qos.logback/logback-classic {:mvn/version "1.2.11" :exclusions [org.slf4j/slf4j-api]} org.slf4j/jcl-over-slf4j {:mvn/version "1.7.36"} diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index daa4da3f..085118c6 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -4,11 +4,12 @@ [clojure.pprint :as pp] [clojure.java.io :refer [file]] [clojure.test :refer [deftest is use-fixtures]] + [clojure.string :as str] [ring.adapter.jetty :as ring]) (:import (java.io ByteArrayInputStream) - (org.eclipse.jetty.server Server) - (org.eclipse.jetty.server.nio SelectChannelConnector) - (org.eclipse.jetty.server.ssl SslSelectChannelConnector))) + (org.eclipse.jetty.server Server ServerConnector))) + +(set! *warn-on-reflection* true) (defn handler [req] (condp = [(:request-method req) (:uri req)] @@ -42,21 +43,18 @@ (def ^:dynamic *server* nil) -(defn current-port [] +(defn- port-for-protocol [p] (let [^Server s *server*] - (->> s - .getConnectors - (filter (comp #{SelectChannelConnector} class)) - ^SelectChannelConnector (first) - .getLocalPort))) + (some (fn [^ServerConnector c] + (when (str/starts-with? (str/lower-case (.getDefaultProtocol c)) p) + (.getLocalPort c))) + (.getConnectors s)))) + +(defn current-port [] + (port-for-protocol "http/")) (defn current-https-port [] - (let [^Server s *server*] - (->> s - .getConnectors - (filter (comp #{SslSelectChannelConnector} class)) - ^SslSelectChannelConnector (first) - .getLocalPort))) + (port-for-protocol "ssl")) (defn with-server [t] (let [s (make-server)] From 2492dead9f1ca7d0f33f41ec57a5498d039f615d Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 15 Aug 2022 09:19:56 -0400 Subject: [PATCH 098/143] dev: add clj-kondo source code linting (#30) Includes the addressing of reported lint findings. Closes #28 --- .clj-kondo/babashka/fs/config.edn | 1 + .clj-kondo/config.edn | 2 + .clj-kondo/lread/status-line/config.edn | 2 + .clj-kondo/rewrite-clj/rewrite-clj/config.edn | 5 ++ .github/workflows/ci.yml | 42 ++++++++++++ README.md | 6 ++ bb.edn | 7 +- bb/lint.clj | 64 +++++++++++++++++++ deps.edn | 6 +- src/clj_http/lite/core.clj | 5 +- test/clj_http/test/client.clj | 21 +++--- test/clj_http/test/cookies.clj | 4 +- test/clj_http/test/core.clj | 5 +- test/setup.clj | 4 +- 14 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 .clj-kondo/babashka/fs/config.edn create mode 100644 .clj-kondo/config.edn create mode 100644 .clj-kondo/lread/status-line/config.edn create mode 100644 .clj-kondo/rewrite-clj/rewrite-clj/config.edn create mode 100644 bb/lint.clj diff --git a/.clj-kondo/babashka/fs/config.edn b/.clj-kondo/babashka/fs/config.edn new file mode 100644 index 00000000..23f36094 --- /dev/null +++ b/.clj-kondo/babashka/fs/config.edn @@ -0,0 +1 @@ +{:lint-as {babashka.fs/with-temp-dir clojure.core/let}} diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn new file mode 100644 index 00000000..a5e368d5 --- /dev/null +++ b/.clj-kondo/config.edn @@ -0,0 +1,2 @@ +;; don't adopt any user preferences +{:config-paths ^:replace []} diff --git a/.clj-kondo/lread/status-line/config.edn b/.clj-kondo/lread/status-line/config.edn new file mode 100644 index 00000000..ac284abe --- /dev/null +++ b/.clj-kondo/lread/status-line/config.edn @@ -0,0 +1,2 @@ +{:lint-as {lread.status-line/line clojure.tools.logging/infof + lread.status-line/die clojure.tools.logging/infof}} diff --git a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn new file mode 100644 index 00000000..19ecae96 --- /dev/null +++ b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn @@ -0,0 +1,5 @@ +{:lint-as + {rewrite-clj.zip/subedit-> clojure.core/-> + rewrite-clj.zip/subedit->> clojure.core/->> + rewrite-clj.zip/edit-> clojure.core/-> + rewrite-clj.zip/edit->> clojure.core/->>}} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 469c1999..50ab3fa3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,47 @@ name: Tests on: [push, pull_request] jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3.0.2 + + - name: Clojure deps cache + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository + ~/.deps.clj + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} + restore-keys: cljdeps- + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + + - name: Setup Clojure Tooling + uses: DeLaGuardo/setup-clojure@9.4 + with: + bb: 'latest' + + - name: Tools versions + run: | + echo "bb --version" + bb --version + echo "java -version" + java -version + + - name: Bring down deps + run: bb deps + + - name: Lint + run: bb lint + test: runs-on: ${{ matrix.os }}-latest strategy: @@ -101,6 +142,7 @@ jobs: deploy: runs-on: ubuntu-latest needs: + - lint - test - bb-test diff --git a/README.md b/README.md index 33fdb8e4..7d69e945 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,12 @@ To run a small suite of sanity tests for babashka (found under ./bb]): $ bb test:bb +### Linting + +Our CI workflow lints sources with clj-kondo, and you can too! + + $ bb lint + ### Release To release a new version, run `bb publish` which will push a new tag. CI will diff --git a/bb.edn b/bb.edn index 9e15ceb6..6c5bcc0c 100644 --- a/bb.edn +++ b/bb.edn @@ -1,5 +1,7 @@ {:paths ["." "bb"] - :deps {org.clj-commons/clj-http-lite {:local/root "."}} + :deps {org.clj-commons/clj-http-lite {:local/root "."} + lread/status-line {:git/url "https://github.com/lread/status-line.git" + :sha "35ed39645038e81b42cb15ed6753b8462e60a06d"}} :tasks {:requires ([tasks :as t]) deps @@ -11,6 +13,9 @@ test:bb {:doc "Run babashka tests" :task clj-http.lite.test-runner/-main} + lint + {:doc "[--rebuild] Lint source code" + :task lint/-main} publish {:doc "Trigger a release to clojars" :task (t/publish)}}} diff --git a/bb/lint.clj b/bb/lint.clj new file mode 100644 index 00000000..d70b5934 --- /dev/null +++ b/bb/lint.clj @@ -0,0 +1,64 @@ +(ns lint + (:require [babashka.classpath :as bbcp] + [babashka.cli :as cli] + [babashka.fs :as fs] + [babashka.tasks :as t] + [clojure.string :as string] + [lread.status-line :as status])) + +(def clj-kondo-cache ".clj-kondo/.cache") + +(defn- cache-exists? [] + (fs/exists? clj-kondo-cache)) + +(defn- delete-cache [] + (when (cache-exists?) + (fs/delete-tree clj-kondo-cache))) + +(defn- build-cache [] + (when (cache-exists?) + (delete-cache)) + (let [clj-cp (-> (t/clojure {:out :string} + "-Spath -M:test") + with-out-str + string/trim) + bb-cp (bbcp/get-classpath)] + (status/line :detail "- copying configs") + (t/clojure "-M:clj-kondo --skip-lint --copy-configs --lint" clj-cp bb-cp) + (status/line :detail "- creating cache") + (t/clojure "-M:clj-kondo --dependencies --lint" clj-cp bb-cp))) + +(defn- check-cache [{:keys [rebuild]}] + (status/line :head "clj-kondo: cache check") + (if-let [rebuild-reason (cond + rebuild + "Rebuild requested" + + (not (cache-exists?)) + "Cache not found" + + :else + (let [updated-dep-files (fs/modified-since clj-kondo-cache ["deps.edn" "bb.edn"])] + (when (seq updated-dep-files) + (format "Found deps files newer than lint cache: %s" (mapv str updated-dep-files)))))] + (do (status/line :detail rebuild-reason) + (build-cache)) + (status/line :detail "Using existing cache"))) + +(defn- lint [opts] + (check-cache opts) + (status/line :head "clj-kondo: linting") + (let [{:keys [exit]} + (t/clojure {:continue true} + "-M:clj-kondo --lint src test bb deps.edn bb.edn")] + (cond + (= 2 exit) (status/die exit "clj-kondo found one or more lint errors") + (= 3 exit) (status/die exit "clj-kondo found one or more lint warnings") + (> exit 0) (status/die exit "clj-kondo returned unexpected exit code")))) + +(defn -main [& args] + (when-let [opts (cli/parse-opts args)] + (lint opts))) + +(when (= *file* (System/getProperty "babashka.file")) + (apply -main *command-line-args*)) diff --git a/deps.edn b/deps.edn index a6e23a27..65c6bf8c 100644 --- a/deps.edn +++ b/deps.edn @@ -21,4 +21,8 @@ org.slf4j/log4j-over-slf4j {:mvn/version "1.7.36"}} :main-opts ["-m" "cognitect.test-runner" ;; our test namespaces do not always end in -test, hence the override: - "--namespace-regex" "clj-http\\.test\\..*"]}}} + "--namespace-regex" "clj-http\\.test\\..*"]} + ;; for consistent linting we use a specific version of clj-kondo through the jvm + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2022.08.03"}} + :override-deps {org.clojure/clojure {:mvn/version "1.11.1"}} + :main-opts ["-m" "clj-kondo.main"]}}} diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 007f5df9..4b85ba03 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -2,8 +2,7 @@ "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) (:import (java.io ByteArrayOutputStream InputStream) - (java.net URL HttpURLConnection) - (java.security SecureRandom))) + (java.net URL HttpURLConnection))) (set! *warn-on-reflection* true) @@ -82,7 +81,7 @@ the clj-http uses ByteArrays for the bodies." [{:keys [request-method scheme server-name server-port uri query-string headers content-type character-encoding body socket-timeout - conn-timeout debug insecure? save-request? follow-redirects + conn-timeout insecure? save-request? follow-redirects chunk-size] :as req}] (let [http-url (str (name scheme) "://" server-name (when server-port (str ":" server-port)) diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index 1d0a7ae9..24100c2a 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -1,10 +1,9 @@ (ns clj-http.test.client (:require [clj-http.lite.client :as client] - [clj-http.test.core :refer [base-req current-port with-server]] + [clj-http.test.core :refer [base-req with-server]] [clj-http.lite.util :as util] [clojure.test :refer [deftest is testing use-fixtures]]) - (:import (java.net UnknownHostException) - (java.util Arrays))) + (:import (java.net UnknownHostException))) (use-fixtures :each with-server) @@ -72,19 +71,19 @@ (is (= "ok" (:body resp))))) (deftest throw-on-exceptional - (let [client (fn [req] {:status 500}) + (let [client (fn [_req] {:status 500}) e-client (client/wrap-exceptions client)] (is (thrown-with-msg? Exception #"500" (e-client {}))))) (deftest pass-on-non-exceptional - (let [client (fn [req] {:status 200}) + (let [client (fn [_req] {:status 200}) e-client (client/wrap-exceptions client) resp (e-client {})] (is (= 200 (:status resp))))) (deftest pass-on-exceptional-when-surpressed - (let [client (fn [req] {:status 500}) + (let [client (fn [_req] {:status 500}) e-client (client/wrap-exceptions client) resp (e-client {:throw-exceptions false})] (is (= 500 (:status resp))))) @@ -110,7 +109,7 @@ (is (= "barbarbar⒝⒜⒭" (util/utf8-string (:body resp)))))) (deftest pass-on-non-compressed - (let [c-client (client/wrap-decompression (fn [req] {:body "foo"})) + (let [c-client (client/wrap-decompression (fn [_req] {:body "foo"})) resp (c-client {:uri "/foo"})] (is (= "foo" (:body resp))))) @@ -142,24 +141,24 @@ {:uri "/foo"})) (deftest apply-on-utf8-output-coercion - (let [client (fn [req] {:body (util/utf8-bytes "fooⓕⓞⓞ")}) + (let [client (fn [_req] {:body (util/utf8-bytes "fooⓕⓞⓞ")}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo"})] (is (= "fooⓕⓞⓞ" (:body resp))))) (deftest apply-on-other-output-coercion - (let [client (fn [req] {:body (.getBytes "sõme ßÒññÝ chÀråcters" "windows-1252") + (let [client (fn [_req] {:body (.getBytes "sõme ßÒññÝ chÀråcters" "windows-1252") :headers {"content-type" "text/foo;charset=windows-1252"}}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo" :as :auto})] (is (= "sõme ßÒññÝ chÀråcters" (:body resp))))) (deftest pass-on-no-output-coercion - (let [client (fn [req] {:body nil}) + (let [client (fn [_req] {:body nil}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo"})] (is (nil? (:body resp)))) - (let [client (fn [req] {:body :thebytes}) + (let [client (fn [_req] {:body :thebytes}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo" :as :byte-array})] (is (= :thebytes (:body resp))))) diff --git a/test/clj_http/test/cookies.clj b/test/clj_http/test/cookies.clj index 704ebc12..bbd63eea 100644 --- a/test/clj_http/test/cookies.clj +++ b/test/clj_http/test/cookies.clj @@ -1,6 +1,6 @@ (ns clj-http.test.cookies - (:use [clj-http.lite.util] - [clojure.test])) + #_(:use [clj-http.lite.util] + [clojure.test])) ;; (defn refer-private [ns] ;; (doseq [[symbol var] (ns-interns ns)] diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 085118c6..3b7b1a1e 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -1,13 +1,10 @@ (ns clj-http.test.core (:require [clj-http.lite.core :as core] [clj-http.lite.util :as util] - [clojure.pprint :as pp] - [clojure.java.io :refer [file]] [clojure.test :refer [deftest is use-fixtures]] [clojure.string :as str] [ring.adapter.jetty :as ring]) - (:import (java.io ByteArrayInputStream) - (org.eclipse.jetty.server Server ServerConnector))) + (:import (org.eclipse.jetty.server Server ServerConnector))) (set! *warn-on-reflection* true) diff --git a/test/setup.clj b/test/setup.clj index 976a6f79..8e1a98d7 100644 --- a/test/setup.clj +++ b/test/setup.clj @@ -1,12 +1,10 @@ (ns setup "This namespace will be automaticaly loaded by the test runner" - (:require - [clojure.string :as string]) (:import (org.eclipse.jetty.util MultiException))) (-> (reify Thread$UncaughtExceptionHandler - (uncaughtException [_ thread e] + (uncaughtException [_ _thread e] ;; Omit exceptions coming from "Address already in use" because they're meaningless ;; (these happen when one picks port 0, and after one such exception a new port will be retried successfully) (let [omit? (or (-> ^Throwable e .getMessage #{"Address already in use"}) From 34ee80ce258f2d726811d1583f3b27d96f3fd0b5 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 15 Aug 2022 11:39:19 -0400 Subject: [PATCH 099/143] docs: readme: add short history [skip ci] (#31) --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d69e945..6e17932e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) ## Differences from clj-http -- Instead of Apache HTTP client, clj-http-lite uses HttpURLConnection +- Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection - No automatic JSON decoding for response bodies - No cookie support - No proxy-ing DELETEs with body @@ -24,6 +24,13 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) - No persistent connection support - namespace rename clj-http.* -> clj-http.lite.* +## History + +- Sep 2011 - [dakrone/clj-http](https://github.com/dakrone/clj-http) created (and is still actively maintained) +- Feb 2012 - [hiredman/clj-http-lite](https://github.com/hiredman/clj-http-lite) (now archived) forked from `dakrone/clj-http` to use Java's HttpURLConnection instead of Apache HttpClient. +- Jul 2018 - `martinklepsch/clj-http-lite` forked from `hiredman/clj-http-lite` for new development and maintenance +- Nov 2021 - Martin transfered his fork to `clj-commons/clj-http-lite` so it could get the ongoing love it needs from the Clojure community + ## Usage The main HTTP client functionality is provided by the From 5aa67f54073fff7dbd0619e82d629c59c576fda0 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 15 Aug 2022 17:25:49 -0400 Subject: [PATCH 100/143] tests: turf special Jetty exception handling (#33) Closes #32 --- test/setup.clj | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 test/setup.clj diff --git a/test/setup.clj b/test/setup.clj deleted file mode 100644 index 8e1a98d7..00000000 --- a/test/setup.clj +++ /dev/null @@ -1,21 +0,0 @@ -(ns setup - "This namespace will be automaticaly loaded by the test runner" - (:import - (org.eclipse.jetty.util MultiException))) - -(-> (reify Thread$UncaughtExceptionHandler - (uncaughtException [_ _thread e] - ;; Omit exceptions coming from "Address already in use" because they're meaningless - ;; (these happen when one picks port 0, and after one such exception a new port will be retried successfully) - (let [omit? (or (-> ^Throwable e .getMessage #{"Address already in use"}) - (and (instance? MultiException e) - (->> ^MultiException e - .getThrowables - (every? (fn [^Throwable t] - (-> t .getMessage (.contains "Address already in use")))))))] - (when-not omit? - (-> ^Throwable e .printStackTrace) - (when (System/getenv "CI") - (System/exit 1)))))) - - (Thread/setDefaultUncaughtExceptionHandler)) From 697705f356453515872baf3aa971981d8da0f3ab Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 16 Aug 2022 12:10:21 -0400 Subject: [PATCH 101/143] User info from URL now applied to basic auth (#37) Also moved wrap-oauth to match clj-http wrapper ordering for easier ongoing comparison. Fixes #34 --- CHANGELOG.md | 1 + src/clj_http/lite/client.clj | 8 +++++--- test/clj_http/test/client.clj | 37 ++++++++++++++++++++++++++++++++++- test/clj_http/test/core.clj | 24 ++++++++++++++++++++--- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad8bbfd3..ee6a5d6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### Unreleased - If specified, request's body encoding is now applied, else defaults to UTF-8 ([#18](https://github.com/clj-commons/clj-http-lite/issues/18)) ([@lread](https://github.com/lread)) +- User info from request URL now applied to basic auth ([#34](https://github.com/clj-commons/clj-http-lite/issues/34)) ([@lread](https://github.com/lread)) - Quality - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index df0f7fb1..80b51a78 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -236,8 +236,12 @@ "Returns a battaries-included HTTP request function coresponding to the given core client. See client/client." [request] + ;; note to the uninitiated: wrapper behaviour is applied to requests in order listed here but + ;; from last to first (-> request wrap-query-params + wrap-basic-auth + wrap-oauth wrap-user-info wrap-url wrap-redirects @@ -245,15 +249,13 @@ wrap-input-coercion wrap-output-coercion wrap-exceptions - wrap-basic-auth wrap-accept wrap-accept-encoding wrap-content-type wrap-form-params wrap-method wrap-links - wrap-unknown-host - wrap-oauth)) + wrap-unknown-host)) (def #^{:doc "Executes the HTTP request corresponding to the given map and returns diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client.clj index 24100c2a..cdd794c4 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client.clj @@ -1,6 +1,6 @@ (ns clj-http.test.client (:require [clj-http.lite.client :as client] - [clj-http.test.core :refer [base-req with-server]] + [clj-http.test.core :refer [base-req with-server current-port]] [clj-http.lite.util :as util] [clojure.test :refer [deftest is testing use-fixtures]]) (:import (java.net UnknownHostException))) @@ -19,6 +19,41 @@ (is (= 200 (:status resp))) (is (= "get" (:body resp))))) +(deftest ^{:integration true} basic-auth-no-creds + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :throw-exceptions false}))] + (is (= 401 (:status resp))) + (is (= "denied" (:body resp))))) + +(deftest ^{:integration true} basic-auth-bad-creds + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :throw-exceptions false + :basic-auth "username:nope"}))] + (is (= 401 (:status resp))) + (is (= "denied" (:body resp))))) + +(deftest ^{:integration true} basic-auth-creds-as-basic-auth + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :basic-auth "username:password"}))] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) + +(deftest ^{:integration true} basic-auth-creds-as-user-info + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :user-info "username:password"}))] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) + +(deftest ^{:integration true} basic-auth-creds-from-url + (let [resp (client/request {:method :get + :url (format "http://username:password@localhost:%d/basic-auth" (current-port))})] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) + (defn is-passed [middleware req] (let [client (middleware identity)] (is (= req (client req))))) diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core.clj index 3b7b1a1e..e9ddef34 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core.clj @@ -4,10 +4,17 @@ [clojure.test :refer [deftest is use-fixtures]] [clojure.string :as str] [ring.adapter.jetty :as ring]) - (:import (org.eclipse.jetty.server Server ServerConnector))) + (:import (org.eclipse.jetty.server Server ServerConnector) + (java.util Base64))) (set! *warn-on-reflection* true) +(defn b64-decode [^String s] + (when s + (-> (Base64/getDecoder) + (.decode s) + util/utf8-string))) + (defn handler [req] (condp = [(:request-method req) (:uri req)] [:get "/get"] @@ -20,7 +27,7 @@ {:status 200 :body (get-in req [:headers "x-my-header"])} [:post "/post"] {:status 200 :body (slurp (:body req))} - [:get "/redirect"] {:status 302 :headers {"Location" "/get"} } + [:get "/redirect"] {:status 302 :headers {"Location" "/get"}} [:get "/error"] {:status 500 :body "o noes"} [:get "/timeout"] @@ -28,7 +35,17 @@ (Thread/sleep 10) {:status 200 :body "timeout"}) [:delete "/delete-with-body"] - {:status 200 :body "delete-with-body"})) + {:status 200 :body "delete-with-body"} + ;; minimal to support testing + [:get "/basic-auth"] + (let [cred (some->> (get (:headers req) "authorization") + (re-find #"^Basic (.*)$") + last + b64-decode) + [user pass] (and cred (str/split cred #":"))] + (if (and (= "username" user) (= "password" pass)) + {:status 200 :body "welcome"} + {:status 401 :body "denied"})))) (defn make-server ^Server [] (ring/run-jetty handler {:port 0 ;; Use a free port @@ -204,3 +221,4 @@ (let [stream (:body (request {:request-method :get :uri "/get" :as :stream})) body (slurp stream)] (is (= "get" body)))) + From b48c2d955809bfb7832eae868b2636f1e16029af Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 16 Aug 2022 12:31:46 -0400 Subject: [PATCH 102/143] tests: rename test namespaces to end in -test (#38) It is what most folks and tools expect these days. Closes #35 --- deps.edn | 4 +--- test/clj_http/test/{client.clj => client_test.clj} | 4 ++-- test/clj_http/test/{cookies.clj => cookies_test.clj} | 2 +- test/clj_http/test/{core.clj => core_test.clj} | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) rename test/clj_http/test/{client.clj => client_test.clj} (99%) rename test/clj_http/test/{cookies.clj => cookies_test.clj} (99%) rename test/clj_http/test/{core.clj => core_test.clj} (99%) diff --git a/deps.edn b/deps.edn index 65c6bf8c..61113769 100644 --- a/deps.edn +++ b/deps.edn @@ -19,9 +19,7 @@ org.slf4j/jcl-over-slf4j {:mvn/version "1.7.36"} org.slf4j/jul-to-slf4j {:mvn/version "1.7.36"} org.slf4j/log4j-over-slf4j {:mvn/version "1.7.36"}} - :main-opts ["-m" "cognitect.test-runner" - ;; our test namespaces do not always end in -test, hence the override: - "--namespace-regex" "clj-http\\.test\\..*"]} + :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2022.08.03"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.1"}} diff --git a/test/clj_http/test/client.clj b/test/clj_http/test/client_test.clj similarity index 99% rename from test/clj_http/test/client.clj rename to test/clj_http/test/client_test.clj index cdd794c4..b1cc06a2 100644 --- a/test/clj_http/test/client.clj +++ b/test/clj_http/test/client_test.clj @@ -1,6 +1,6 @@ -(ns clj-http.test.client +(ns clj-http.test.client-test (:require [clj-http.lite.client :as client] - [clj-http.test.core :refer [base-req with-server current-port]] + [clj-http.test.core-test :refer [base-req with-server current-port]] [clj-http.lite.util :as util] [clojure.test :refer [deftest is testing use-fixtures]]) (:import (java.net UnknownHostException))) diff --git a/test/clj_http/test/cookies.clj b/test/clj_http/test/cookies_test.clj similarity index 99% rename from test/clj_http/test/cookies.clj rename to test/clj_http/test/cookies_test.clj index bbd63eea..283ae8c5 100644 --- a/test/clj_http/test/cookies.clj +++ b/test/clj_http/test/cookies_test.clj @@ -1,4 +1,4 @@ -(ns clj-http.test.cookies +(ns clj-http.test.cookies-test #_(:use [clj-http.lite.util] [clojure.test])) diff --git a/test/clj_http/test/core.clj b/test/clj_http/test/core_test.clj similarity index 99% rename from test/clj_http/test/core.clj rename to test/clj_http/test/core_test.clj index e9ddef34..9a920140 100644 --- a/test/clj_http/test/core.clj +++ b/test/clj_http/test/core_test.clj @@ -1,4 +1,4 @@ -(ns clj-http.test.core +(ns clj-http.test.core-test (:require [clj-http.lite.core :as core] [clj-http.lite.util :as util] [clojure.test :refer [deftest is use-fixtures]] From 4a01538a2b93d0bc3df0d59eaad9a5f88a95ece8 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 16 Aug 2022 12:50:56 -0400 Subject: [PATCH 103/143] tests: deal with commented out tests (#39) Turf: - Cookies tests, our README states we don't support cookies - A header conversion test (Apache HttpClient specific, not relevant for us, we use HttpURLConnection) Enable: - Delete with body test, this has been fixed since JDK8. Update README accordingly. Closes #26 --- README.md | 1 - test/clj_http/test/cookies_test.clj | 209 ---------------------------- test/clj_http/test/core_test.clj | 39 +----- 3 files changed, 5 insertions(+), 244 deletions(-) delete mode 100644 test/clj_http/test/cookies_test.clj diff --git a/README.md b/README.md index 6e17932e..3bfd58eb 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) - Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection - No automatic JSON decoding for response bodies - No cookie support -- No proxy-ing DELETEs with body - No multipart form uploads - No persistent connection support - namespace rename clj-http.* -> clj-http.lite.* diff --git a/test/clj_http/test/cookies_test.clj b/test/clj_http/test/cookies_test.clj deleted file mode 100644 index 283ae8c5..00000000 --- a/test/clj_http/test/cookies_test.clj +++ /dev/null @@ -1,209 +0,0 @@ -(ns clj-http.test.cookies-test - #_(:use [clj-http.lite.util] - [clojure.test])) - -;; (defn refer-private [ns] -;; (doseq [[symbol var] (ns-interns ns)] -;; (when (:private (meta var)) -;; (intern *ns* symbol var)))) - -;; (refer-private 'clj-http.cookies) - -;; (def session (str "ltQGXSNp7cgNeFG6rPE06qzriaI+R8W7zJKFu4UOlX4=-" -;; "-lWgojFmZlDqSBnYJlUmwhqXL4OgBTkra5WXzi74v+nE=")) - -;; (deftest test-compact-map -;; (are [map expected] -;; (is (= expected (compact-map map))) -;; {:a nil :b 2 :c 3 :d nil} -;; {:b 2 :c 3} -;; {:comment nil :domain "example.com" :path "/" :ports [80 8080] :value 1} -;; {:domain "example.com" :path "/" :ports [80 8080] :value 1})) - -;; (deftest test-decode-cookie -;; (are [set-cookie-str expected] -;; (is (= expected (decode-cookie set-cookie-str))) -;; nil nil -;; "" nil -;; "example-cookie=example-value;Path=/" -;; ["example-cookie" -;; {:discard true :path "/" :value "example-value" :version 0}] -;; "example-cookie=example-value;Domain=.example.com;Path=/" -;; ["example-cookie" -;; {:discard true :domain ".example.com" :path "/" -;; :value "example-value" :version 0}])) - -;; (deftest test-decode-cookies-with-seq -;; (let [cookies (decode-cookies [(str "ring-session=" (url-encode session))])] -;; (is (map? cookies)) -;; (is (= 1 (count cookies))) -;; (let [cookie (get cookies "ring-session")] -;; (is (= true (:discard cookie))) -;; (is (nil? (:domain cookie))) -;; (is (= "/" (:path cookie))) -;; (is (= session (:value cookie))) -;; (is (= 0 (:version cookie)))))) - -;; (deftest test-decode-cookies-with-string -;; (let [cookies (decode-cookies -;; (str "ring-session=" (url-encode session) ";Path=/"))] -;; (is (map? cookies)) -;; (is (= 1 (count cookies))) -;; (let [cookie (get cookies "ring-session")] -;; (is (= true (:discard cookie))) -;; (is (nil? (:domain cookie))) -;; (is (= "/" (:path cookie))) -;; (is (= session (:value cookie))) -;; (is (= 0 (:version cookie)))))) - -;; (deftest test-decode-cookie-header -;; (are [response expected] -;; (is (= expected (decode-cookie-header response))) -;; {:headers {"set-cookie" "a=1"}} -;; {:cookies {"a" {:discard true :path "/" -;; :value "1" :version 0}} :headers {}} -;; {:headers {"set-cookie" -;; (str "ring-session=" (url-encode session) ";Path=/")}} -;; {:cookies {"ring-session" -;; {:discard true :path "/" -;; :value session :version 0}} :headers {}})) - -;; (deftest test-encode-cookie -;; (are [cookie expected] -;; (is (= expected (encode-cookie cookie))) -;; [:a {:value "b"}] "a=b" -;; ["a" {:value "b"}] "a=b" -;; ["example-cookie" -;; {:domain ".example.com" :path "/" :value "example-value"}] -;; "example-cookie=example-value" -;; ["ring-session" {:value session}] -;; (str "ring-session=" (url-encode session)))) - -;; (deftest test-encode-cookies -;; (are [cookie expected] -;; (is (= expected (encode-cookies cookie))) -;; {:a {:value "b"} :c {:value "d"} :e {:value "f"}} -;; "a=b;c=d;e=f" -;; {"a" {:value "b"} "c" {:value "d"} "e" {:value "f"}} -;; "a=b;c=d;e=f" -;; {"example-cookie" -;; {:domain ".example.com" :path "/" :value "example-value"}} -;; "example-cookie=example-value" -;; {"example-cookie" -;; {:domain ".example.com" :path "/" :value "example-value" -;; :discard true :version 0}} -;; "example-cookie=example-value" -;; {"ring-session" {:value session}} -;; (str "ring-session=" (url-encode session)))) - -;; (deftest test-encode-cookie-header -;; (are [request expected] -;; (is (= expected (encode-cookie-header request))) -;; {:cookies {"a" {:value "1"}}} -;; {:headers {"Cookie" "a=1"}} -;; {:cookies -;; {"example-cookie" {:domain ".example.com" :path "/" -;; :value "example-value"}}} -;; {:headers {"Cookie" "example-cookie=example-value"}})) - -;; (deftest test-to-basic-client-cookie-with-simple-cookie -;; (let [cookie (to-basic-client-cookie -;; ["ring-session" -;; {:value session -;; :path "/" -;; :domain "example.com"}])] -;; (is (= "ring-session" (.getName cookie))) -;; (is (= (url-encode session) (.getValue cookie))) -;; (is (= "/" (.getPath cookie))) -;; (is (= "example.com" (.getDomain cookie))) -;; (is (nil? (.getComment cookie))) -;; (is (nil? (.getCommentURL cookie))) -;; (is (not (.isPersistent cookie))) -;; (is (nil? (.getExpiryDate cookie))) -;; (is (nil? (seq (.getPorts cookie)))) -;; (is (not (.isSecure cookie))) -;; (is (= 0 (.getVersion cookie))))) - -;; (deftest test-to-basic-client-cookie-with-full-cookie -;; (let [cookie (to-basic-client-cookie -;; ["ring-session" -;; {:value session -;; :path "/" -;; :domain "example.com" -;; :comment "Example Comment" -;; :comment-url "http://example.com/cookies" -;; :discard true -;; :expires (java.util.Date. (long 0)) -;; :ports [80 8080] -;; :secure true -;; :version 0}])] -;; (is (= "ring-session" (.getName cookie))) -;; (is (= (url-encode session) (.getValue cookie))) -;; (is (= "/" (.getPath cookie))) -;; (is (= "example.com" (.getDomain cookie))) -;; (is (= "Example Comment" (.getComment cookie))) -;; (is (= "http://example.com/cookies" (.getCommentURL cookie))) -;; (is (not (.isPersistent cookie))) -;; (is (= (java.util.Date. (long 0)) (.getExpiryDate cookie))) -;; (is (= [80 8080] (seq (.getPorts cookie)))) -;; (is (.isSecure cookie)) -;; (is (= 0 (.getVersion cookie))))) - -;; (deftest test-to-basic-client-cookie-with-symbol-as-name -;; (let [cookie (to-basic-client-cookie -;; [:ring-session {:value session :path "/" -;; :domain "example.com"}])] -;; (is (= "ring-session" (.getName cookie))))) - -;; (deftest test-to-cookie-with-simple-cookie -;; (let [[name content] -;; (to-cookie -;; (doto (BasicClientCookie. "example-cookie" "example-value") -;; (.setDomain "example.com") -;; (.setPath "/")))] -;; (is (= "example-cookie" name)) -;; (is (nil? (:comment content))) -;; (is (nil? (:comment-url content))) -;; (is (:discard content)) -;; (is (= "example.com" (:domain content))) -;; (is (nil? (:expires content))) -;; (is (nil? (:ports content))) -;; (is (not (:secure content))) -;; (is (= 0 (:version content))) -;; (is (= "example-value" (:value content))))) - -;; (deftest test-to-cookie-with-full-cookie -;; (let [[name content] -;; (to-cookie -;; (doto (BasicClientCookie2. "example-cookie" "example-value") -;; (.setComment "Example Comment") -;; (.setCommentURL "http://example.com/cookies") -;; (.setDiscard true) -;; (.setDomain "example.com") -;; (.setExpiryDate (java.util.Date. (long 0))) -;; (.setPath "/") -;; (.setPorts (int-array [80 8080])) -;; (.setSecure true) -;; (.setVersion 1)))] -;; (is (= "example-cookie" name)) -;; (is (= "Example Comment" (:comment content))) -;; (is (= "http://example.com/cookies" (:comment-url content))) -;; (is (= true (:discard content))) -;; (is (= "example.com" (:domain content))) -;; (is (= (java.util.Date. (long 0)) (:expires content))) -;; (is (= [80 8080] (:ports content))) -;; (is (= true (:secure content))) -;; (is (= 1 (:version content))) -;; (is (= "example-value" (:value content))))) - -;; (deftest test-wrap-cookies -;; (is (= {:cookies {"example-cookie" {:discard true :domain ".example.com" -;; :path "/" :value "example-value" -;; :version 0}} :headers {}} -;; ((wrap-cookies -;; (fn [request] -;; (is (= (get (:headers request) "Cookie") "a=1;b=2")) -;; {:headers -;; {"set-cookie" -;; "example-cookie=example-value;Domain=.example.com;Path=/"}})) -;; {:cookies {:a {:value "1"} :b {:value "2"}}})))) diff --git a/test/clj_http/test/core_test.clj b/test/clj_http/test/core_test.clj index 9a920140..47d7cd1f 100644 --- a/test/clj_http/test/core_test.clj +++ b/test/clj_http/test/core_test.clj @@ -156,12 +156,11 @@ (is (or (= java.net.SocketTimeoutException (class e)) (= java.net.SocketTimeoutException (class (.getCause e)))))))) -;; HUC can't do this -;; (deftest ^{:integration true} delete-with-body -;; (run-server) -;; (let [resp (request {:request-method :delete :uri "/delete-with-body" -;; :body (.getBytes "foo bar")})] -;; (is (= 200 (:status resp))))) +(deftest ^{:integration true} delete-with-body + (let [resp (request {:request-method :delete :uri "/delete-with-body" + :body (.getBytes "foo bar")})] + (is (= 200 (:status resp))) + (is (= "delete-with-body" (slurp-body resp))))) (deftest ^{:integration true} self-signed-ssl-get (let [client-opts {:request-method :get @@ -190,35 +189,7 @@ :request (dissoc :body)))))) -;; (deftest parse-headers -;; (are [headers expected] -;; (let [iterator (BasicHeaderIterator. -;; (into-array BasicHeader -;; (map (fn [[name value]] -;; (BasicHeader. name value)) -;; headers)) -;; nil)] -;; (is (= (core/parse-headers iterator) -;; expected))) - -;; [] -;; {} - -;; [["Set-Cookie" "one"]] -;; {"set-cookie" "one"} - -;; [["Set-Cookie" "one"] -;; ["set-COOKIE" "two"]] -;; {"set-cookie" ["one" "two"]} - -;; [["Set-Cookie" "one"] -;; ["serVer" "some-server"] -;; ["set-cookie" "two"]] -;; {"set-cookie" ["one" "two"] -;; "server" "some-server"})) - (deftest ^{:integration true} t-streaming-response (let [stream (:body (request {:request-method :get :uri "/get" :as :stream})) body (slurp stream)] (is (= "get" body)))) - From 9d73e5d325f3bffa71ab02bfd53114faa899f05a Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 16 Aug 2022 19:45:08 -0400 Subject: [PATCH 104/143] docs: review and update docstrings (#41) This exercise helped me to understand the API more deeply, hopefully it will help our users too. The biggest challenge was documenting `clj-http.lite.client/request`. Its previous docstring was way too vague for me to understand, as a user, what is available. Also challenging is the lack of definition of the supported API. I'm guessing our documented API is currently including lots of unnecessary internals. I reviewed all existing docstrings and updated where I thought I could be clearer and/or more consistent. I added no new docstrings. Also: added cljdoc.edn to explicitly list our docs. Closes #36 --- doc/cljdoc.edn | 3 + src/clj_http/lite/client.clj | 108 ++++++++++++++++++++++++++--------- src/clj_http/lite/core.clj | 15 ++--- src/clj_http/lite/links.clj | 6 +- src/clj_http/lite/util.clj | 22 +++---- 5 files changed, 104 insertions(+), 50 deletions(-) create mode 100644 doc/cljdoc.edn diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn new file mode 100644 index 00000000..e942b3f9 --- /dev/null +++ b/doc/cljdoc.edn @@ -0,0 +1,3 @@ +{:cljdoc.doc/tree + [["Readme" {:file "README.md"}] + ["Changelog" {:file "CHANGELOG.md"}]]} diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index 80b51a78..442e3f58 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -1,5 +1,8 @@ (ns clj-http.lite.client - "Batteries-included HTTP client." + "Batteries-included HTTP client. + + Among the many functions here you'll likely be most interested in + [[get]] [[head]] [[put]] [[post]] [[delete]] or the slightly lower level [[request]]." (:require [clj-http.lite.core :as core] [clj-http.lite.links :refer [wrap-links]] [clj-http.lite.util :as util] @@ -233,8 +236,7 @@ (client req)))) (defn wrap-request - "Returns a battaries-included HTTP request function coresponding to the given - core client. See client/client." + "Returns a batteries-included HTTP request function." [request] ;; note to the uninitiated: wrapper behaviour is applied to requests in order listed here but ;; from last to first @@ -257,51 +259,101 @@ wrap-links wrap-unknown-host)) -(def #^{:doc - "Executes the HTTP request corresponding to the given map and returns - the response map for corresponding to the resulting HTTP response. - - In addition to the standard Ring request keys, the following keys are also - recognized: - * :url - * :method - * :query-params - * :basic-auth - * :content-type - * :accept - * :accept-encoding - * :as - - The following additional behaviors over also automatically enabled: - * Exceptions are thrown for status codes other than 200-207, 300-303, or 307 - * Gzip and deflate responses are accepted and decompressed - * Input and output bodies are coerced as required and indicated by the :as - option."} +(def ^{:arglists '([req])} request + "Returns response map for executed HTTP `req` map. + + Notice that some `req` key entries will be overwritten by automatic conversion to other key entries: + + Request method + * `:method` - ex. `:get`,`:head`,`:post`,`:put`,`:delete`, converts to `:request-method` with same value + + Request URL + * `:url` - ex. `\"https://joe:blow@example.com:443/some/path?q=clojure\"`, converts to: + * `:scheme` - protocol `:https` + * `:server-name` - host `\"example.com\"` + * `:server-port` - `443` (if not specified, will be inferred from `:scheme`) + * `:uri` - path `\"/some/path\"` + * `:user-info` - `\"joe:blow\"`, converts to: + * `:basic-auth` - which automatically converts to appropriate `:headers` + * `:query-string` - `\"q=clojure\"` + * `:query-params` - ex. `{\"q\" \"clojure\"}` or `{:q \"clojure\"}` converts to `:query-string` (see above) + + Request body & headers + * `:body` - can be a string, byte array, File or input stream + * `:body-encoding` - charset ex. `\"UTF-16\"`, defaults to `\"UTF-8\"`, iff `:body` is string converts to: + * `:body` encoded in charset + * `:character-encoding` set to charset which converts to appropriate `:headers` iff `:content-type` also set + * `:content-type` - media type of request body, converts to appropriate `:headers` entry, specify: + * keyword as shorthand, ex. `:json` for `\"application/json\"` + * string for verboten, ex. `\"text/html\"` + * `:form-params` - ex. `{\"q\" \"clojure\"}` or `{:q \"clojure\"}`, iff `:method` is `:post`: converts to: + * urlencoded `:body` + * appropriate `:headers` entry + * `:oauth-token` - bearer authorization token, ex. `\"my70k3nh3r3\"`, converts to appropriate `:headers` entry + * `:basic-auth` - basic authentication, converts to appropriate `:headers` entry, (see also `:url` and `:user-info`), specify: + * vector `[\"uname\" \"pass\"]` becomes `\"uname:pass\"` + * use string for verboten + * `:accept-encoding` - vector of accepted response encodings, ex. `[:gzip :deflate :identity]`, converts to appropriate `:headers` entry + * `:accept` - accept response of media type, converts to appropriate `:headers` entry, specify + * keyword as shorthand, ex. `:json` for `\"application/json\"` + * string for verboten, ex. `\"text/html\"` + * `:headers` - explicitly set request headers, ex. `{\"Cache-Control\" \"no-cache\"}` + + Request behaviour + * `:as` - specifies how response body should be coerced: + * `:stream` + * `:byte-array` + * `:auto` - to string decoded with `charset` in response `:headers` `content-type` `charset` else UTF-8 + * `\"charset\"` - to string decoded with `charset` ex. `\"utf-16\"` + * else - to string decoded with UTF-8 + * `:follow-redirects` - specify `false` to not follow response redirects + * `:throw-exceptions` - specify `false` to not throw on https status error codes + * `:ignore-unknown-host?` - specify `true` to not throw on unknown host + * `:insecure?` - allow connection with an invalid SSL certificate + * `:conn-timeout` - number of milliseconds to wait to establish a connection + * `:socket-timeout` - number of milliseconds to wait for data to be available to read + * `:save-request?` - specify `true` to include ultimate converted `:request` used in response map + * `:chunk-size` - in bytes, enables streaming of HTTP request body with chunk-size bytes, +see [JDK docs](https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html#setChunkedStreamingMode-int-) +for details + + Response map keys: + * `:status` - http status code, see `:throw-exceptions` above + * `:headers` - response headers + * `:body` - response body, gzip and deflate responses are accepted and decompressed. See `:as` above. + * `:request` - see `:save-request?` above + + See [README](/README.md#usage) for example usages." (wrap-request #'core/request)) (defn get - "Like #'request, but sets the :method and :url as appropriate." + "Executes HTTP GET request for `url` and, optionally, more `req` attributes. + See [[request]]." [url & [req]] (request (merge req {:method :get :url url}))) (defn head - "Like #'request, but sets the :method and :url as appropriate." + "Executes HTTP HEAD request for `url` and, optionally, more `req` attributes. + See [[request]]." [url & [req]] (request (merge req {:method :head :url url}))) (defn post - "Like #'request, but sets the :method and :url as appropriate." + "Executes HTTP POST request for `url` and, optionally, more `req` attributes. + See [[request]]." [url & [req]] (request (merge req {:method :post :url url}))) (defn put - "Like #'request, but sets the :method and :url as appropriate." + "Executes HTTP PUT request for `url` and, optionally, more `req` attributes. + See [[request]]." [url & [req]] (request (merge req {:method :put :url url}))) (defn delete - "Like #'request, but sets the :method and :url as appropriate." + "Executes HTTP DELETE request for `url` and, optionally, more `req` attributes. + See [[request]]." [url & [req]] (request (merge req {:method :delete :url url}))) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 4b85ba03..03b5d919 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -7,9 +7,9 @@ (set! *warn-on-reflection* true) (defn parse-headers - "Takes a URLConnection and returns a map of names to values. + "Returns a map of names to values for URLConnection `conn`. - If a name appears more than once (like `set-cookie`) then the value + If a header name appears more than once (like `set-cookie`) then the value will be a vector containing the values in the order they appeared in the headers." [conn] @@ -26,8 +26,8 @@ (vec v)))))))) (defn- coerce-body-entity - "Coerce the http-entity from an HttpResponse to either a byte-array, or a - stream that closes itself and the connection manager when closed." + "Return body response from HttpURLConnection `conn` coerced to either a byte-array, + or a stream." [{:keys [as]} conn] (let [ins (try (.getInputStream ^HttpURLConnection conn) @@ -74,11 +74,8 @@ (def-insecure) (defn request - "Executes the HTTP request corresponding to the given Ring request map and - returns the Ring response map corresponding to the resulting HTTP response. - - Note that where Ring uses InputStreams for the request and response bodies, - the clj-http uses ByteArrays for the bodies." + "Executes the HTTP request corresponding to the given Ring `req` map and + returns the Ring response map corresponding to the resulting HTTP response." [{:keys [request-method scheme server-name server-port uri query-string headers content-type character-encoding body socket-timeout conn-timeout insecure? save-request? follow-redirects diff --git a/src/clj_http/lite/links.clj b/src/clj_http/lite/links.clj index 3456439d..61b35867 100644 --- a/src/clj_http/lite/links.clj +++ b/src/clj_http/lite/links.clj @@ -54,8 +54,10 @@ response)) (defn wrap-links - "Add a :links key to the response map that contains parsed Link headers. The - links will be represented as a map, with the 'rel' value being the key. The + "Returns request wrapper fn for `client` that adds + a `:links` key to the response map that contains parsed link headers. + + The links are returned as a map, with the 'rel' value being the key. The URI is placed under the 'href' key, to mimic the HTML link element. e.g. Link: ; rel=next; title=\"Page 2\" diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index 6e143c81..00344327 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -9,29 +9,29 @@ (set! *warn-on-reflection* true) (defn utf8-bytes - "Returns the UTF-8 bytes corresponding to the given string." + "Returns the UTF-8 bytes for string `s`." [#^String s] (.getBytes s "UTF-8")) (defn utf8-string - "Returns the String corresponding to the UTF-8 decoding of the given bytes." + "Returns the string for UTF-8 decoding of bytes `b`." [#^"[B" b] (String. b "UTF-8")) (defn url-decode - "Returns the form-url-decoded version of the given string, using either a - specified encoding or UTF-8 by default." + "Returns the form-url-decoded version of `encoded` string, using either a + specified `encoding` or UTF-8 by default." [^String encoded & [encoding]] (let [^String encoding (or encoding "UTF-8")] (URLDecoder/decode encoded encoding))) (defn url-encode - "Returns an UTF-8 URL encoded version of the given string." + "Returns an UTF-8 URL encoded version of `unencoded` string." [^String unencoded] (URLEncoder/encode unencoded "UTF-8")) (defmacro base64-encode - "Encode an array of bytes into a base64 encoded string." + "Encode an array of `unencoded` bytes into a base64 encoded string." [unencoded] (if (try (import 'javax.xml.bind.DatatypeConverter) (catch Exception _)) @@ -41,7 +41,7 @@ `(.encodeToString (java.util.Base64/getEncoder) ~unencoded)))) (defn to-byte-array - "Returns a byte array for the InputStream provided." + "Returns a byte array for InputStream `is`." [is] (let [chunk-size 8192 baos (ByteArrayOutputStream.) @@ -54,7 +54,7 @@ (defn gunzip - "Returns a gunzip'd version of the given byte array." + "Returns a gunzip'd version of byte array `b`." [b] (when b (if (instance? InputStream b) @@ -62,7 +62,7 @@ (to-byte-array (GZIPInputStream. (ByteArrayInputStream. b)))))) (defn gzip - "Returns a gzip'd version of the given byte array." + "Returns a gzip'd version byte array `b`." [b] (when b (let [baos (ByteArrayOutputStream.) @@ -72,13 +72,13 @@ (.toByteArray baos)))) (defn inflate - "Returns a zlib inflate'd version of the given byte array." + "Returns a zlib inflate'd version byte array `b`." [b] (when b (to-byte-array (InflaterInputStream. (ByteArrayInputStream. b))))) (defn deflate - "Returns a deflate'd version of the given byte array." + "Returns a deflate'd version byte array `b`." [b] (when b (to-byte-array (DeflaterInputStream. (ByteArrayInputStream. b))))) From 3f5addf1086fcb051a09c3770e426836e8311de1 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 16 Aug 2022 20:00:11 -0400 Subject: [PATCH 105/143] dev cleanup: turf old remnant needed for JDK7 (#42) Our min is JDK8. Simplify code. Closes #40 --- src/clj_http/lite/util.clj | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/clj_http/lite/util.clj b/src/clj_http/lite/util.clj index 00344327..552d11a7 100644 --- a/src/clj_http/lite/util.clj +++ b/src/clj_http/lite/util.clj @@ -3,6 +3,7 @@ (:require [clojure.java.io :as io]) (:import (java.io ByteArrayInputStream ByteArrayOutputStream InputStream) (java.net URLEncoder URLDecoder) + (java.util Base64) (java.util.zip InflaterInputStream DeflaterInputStream GZIPInputStream GZIPOutputStream))) @@ -30,15 +31,10 @@ [^String unencoded] (URLEncoder/encode unencoded "UTF-8")) -(defmacro base64-encode +(defn base64-encode "Encode an array of `unencoded` bytes into a base64 encoded string." [unencoded] - (if (try (import 'javax.xml.bind.DatatypeConverter) - (catch Exception _)) - `(javax.xml.bind.DatatypeConverter/printBase64Binary ~unencoded) - (do - (import 'java.util.Base64) - `(.encodeToString (java.util.Base64/getEncoder) ~unencoded)))) + (.encodeToString (Base64/getEncoder) unencoded)) (defn to-byte-array "Returns a byte array for InputStream `is`." @@ -52,7 +48,6 @@ (recur (.read ^InputStream is buffer 0 chunk-size)))) (.toByteArray baos))) - (defn gunzip "Returns a gunzip'd version of byte array `b`." [b] From 02279a8f85fffc8a6c49d9222b8f84f45a0e4c7a Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 17 Aug 2022 17:23:46 -0400 Subject: [PATCH 106/143] Flatten nested query and form parameter maps (#44) Brought over flattening code from clj-http but not the options to enable/disable flattening. For us, for now, it is always enabled. See updates to README for examples. Closes #43 --- CHANGELOG.md | 2 ++ README.md | 47 +++++++++++++++++++++++++----- src/clj_http/lite/client.clj | 25 +++++++++++++++- test/clj_http/test/client_test.clj | 17 +++++++++++ 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee6a5d6b..30c759d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ - If specified, request's body encoding is now applied, else defaults to UTF-8 ([#18](https://github.com/clj-commons/clj-http-lite/issues/18)) ([@lread](https://github.com/lread)) - User info from request URL now applied to basic auth ([#34](https://github.com/clj-commons/clj-http-lite/issues/34)) ([@lread](https://github.com/lread)) +- Nested query and form parameters are now automatically flattened ([#43](https://github.com/clj-commons/clj-http-lite/issues/43)) ([@lread](https://github.com/lread)) - Quality + - Docstrings reviewed and updated - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) ### 0.4.384 diff --git a/README.md b/README.md index 3bfd58eb..8093e4d9 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,14 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http) - Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection - No automatic JSON decoding for response bodies +- No automatic request body encoding beyond charset and url encoding of form params - No cookie support - No multipart form uploads - No persistent connection support +- Fewer options - namespace rename clj-http.* -> clj-http.lite.* +Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you'd like to see in clj-http-lite. We can discuss. ## History - Sep 2011 - [dakrone/clj-http](https://github.com/dakrone/clj-http) created (and is still actively maintained) @@ -92,6 +95,41 @@ codes. The client transparently accepts and decompresses the `gzip` and `deflate` content encodings. +### Nested params + +Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatically flattened to `a[b]=1`. +We'll use `httpbin.org` to demonstrate: + +```clojure +(-> (client/get "https://httpbin.org/get" + {:query-params {:one {:two 2 :three 3}}}) + :body + println) +{ + "args": { + "one[three]": "3", + "one[two]": "2" + }, + ... +} + +(-> (client/post "https://httpbin.org/post" + {:form-params {:one {:two 2 + :three {:four {:five 5}}} + :six 6}}) + :body + println) +{ + ... + "form": { + "one[three][four][five]": "5", + "one[two]": "2", + "six": "6" + }, + ... +} +``` + ### Input coercion ```clojure @@ -188,18 +226,11 @@ such), check out the ## Known Issues -- Nested form params [aren't serialized correctly](https://github.com/hiredman/clj-http-lite/issues/15). There's an easy workaround however: - - ```clojure - :form-params {"toplevel" {"nested" some-data}} ; doesn't work - :form-params {"toplevel[nested]" some-data} ; works - ``` - - If you issue HTTPS connections, [Native Image](https://www.graalvm.org/docs/reference-manual/native-image/) compilation requires an additional parameter in order to enable its support in the generated image. If you get the following kind of error: - Exception in thread "main" java.net.MalformedURLException: Accessing an URL protocol that was not enabled. + Exception in thread "main" java.net.MalformedURLException: Accessing an URL protocol that was not enabled. The URL protocol https is supported but not enabled by default. It must be enabled by adding the -H:EnableURLProtocols=https option to the native-image command. diff --git a/src/clj_http/lite/client.clj b/src/clj_http/lite/client.clj index 442e3f58..56d0ed36 100644 --- a/src/clj_http/lite/client.clj +++ b/src/clj_http/lite/client.clj @@ -7,7 +7,8 @@ [clj-http.lite.links :refer [wrap-links]] [clj-http.lite.util :as util] [clojure.java.io :as io] - [clojure.string :as str]) + [clojure.string :as str] + [clojure.walk :as walk]) (:import (java.net UnknownHostException) (java.nio.charset Charset)) (:refer-clojure :exclude (get update))) @@ -212,6 +213,27 @@ :body (generate-query-string form-params)))) (client req)))) +(defn- nest-params + [req param-key] + (if-let [params (req param-key)] + (let [nested (walk/prewalk + #(if (and (vector? %) (map? (second %))) + (let [[fk m] %] + (reduce + (fn [m [sk v]] + (assoc m (str (name fk) + \[ (name sk) \]) v)) + {} + m)) + %) + params)] + (assoc req param-key nested)) + req)) + +(defn wrap-nested-params [client] + (fn [req] + (client (-> req (nest-params :form-params) (nest-params :query-params))))) + (defn wrap-url [client] (fn [req] (if-let [url (:url req)] @@ -255,6 +277,7 @@ wrap-accept-encoding wrap-content-type wrap-form-params + wrap-nested-params wrap-method wrap-links wrap-unknown-host)) diff --git a/test/clj_http/test/client_test.clj b/test/clj_http/test/client_test.clj index b1cc06a2..c62b6d85 100644 --- a/test/clj_http/test/client_test.clj +++ b/test/clj_http/test/client_test.clj @@ -299,6 +299,23 @@ (is (= "untouched" (:body resp))) (is (not (contains? resp :content-type)))))) +(deftest apply-on-nest-params + (let [param-client (client/wrap-nested-params identity) + params {:a + {:b + {:c 5} + :e + {:f 6}} + :g 7} + resp (param-client {:form-params params :query-params params})] + (is (= {"a[b][c]" 5 "a[e][f]" 6 :g 7} (:form-params resp) (:query-params resp))))) + +(deftest pass-on-no-nest-params + (let [m-client (client/wrap-nested-params identity) + in {:key :val} + out (m-client in)] + (is (= out in)))) + (deftest t-ignore-unknown-host (is (thrown? UnknownHostException (client/get "http://aorecuf892983a.com"))) (is (nil? (client/get "http://aorecuf892983a.com" From 7c4f254e2d683ea8b5cee8fefe8c3b760d1da815 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 17 Aug 2022 19:56:00 -0400 Subject: [PATCH 107/143] docs: readme: edits [skip ci] (#46) Corrected some links. Minor text changes here and there. All examples tried in REPL and updated to: - hit a live site to encourage the reader to try play in the REPL - updated to https, these were originally written 10 years ago, different times I'm still unsure about - the usage/behaviour of a binary byte body request - the section on fake http requests, is it relevant to clj-http-lite? - the GraalVM known problem, is that just a normal Graal thing? Feels like more of a tip than a problem? - I've not tested the advice on proxies yet --- README.md | 178 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 8093e4d9..e37b2507 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# `clj-http-lite` [![cljdoc badge](https://cljdoc.xyz/badge/org.clj-commons/clj-http-lite)](https://cljdoc.xyz/d/org.clj-commons/clj-http-lite/CURRENT) [![CI](https://github.com/martinklepsch/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/martinklepsch/clj-http-lite/actions) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) +# `clj-http-lite` [![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/clj-http-lite)](https://cljdoc.org/d/org.clj-commons/clj-http-lite) [![CI tests](https://github.com/clj-commons/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/clj-commons/clj-http-lite/actions) [![Clojars](https://img.shields.io/clojars/v/org.clj-commons/clj-http-lite.svg)](https://clojars.org/org.clj-commons/clj-http-lite) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) -A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with GraalVM. +A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with Babashka and GraalVM. > This is a clj-commons maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. @@ -43,28 +43,32 @@ The main HTTP client functionality is provided by the ``` The client supports simple `get`, `head`, `put`, `post`, and `delete` -requests. Responses are returned as Ring-style response maps: +requests. They all return Ring-style response maps: ```clojure -(client/get "http://google.com") +(client/get "https://google.com") => {:status 200 - :headers {"date" "Sun, 01 Aug 2010 07:03:49 GMT" + :headers {"date" "Wed, 17 Aug 2022 21:37:58 GMT" "cache-control" "private, max-age=0" "content-type" "text/html; charset=ISO-8859-1" ...} :body "..."} ``` -More example requests: +**TIP**: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many examples. ```clojure -(client/get "http://site.com/resources/id") +(client/get "https://httpbin.org/user-agent") -(client/get "http://site.com/resources/3" {:accept :json}) +;; Tell the server you'd like a json response +(client/get "https://httpbin.org/user-agent" {:accept :json}) -;; Various options: -(client/post "http://site.com/api" - {:basic-auth ["user" "pass"] +;; Or maybe you'd like html back +(client/get "https://httpbin.org/html" {:accept "text/html"}) + +;; Various options +(client/post "https://httpbin.org/anything" + {:basic-auth ["joe" "cool"] :body "{\"json\": \"input\"}" :headers {"X-Api-Version" "2"} :content-type :json @@ -73,35 +77,41 @@ More example requests: :accept :json}) ;; Need to contact a server with an untrusted SSL cert? -(client/get "https://alioth.debian.org" {:insecure? true}) +(client/get "https://expired.badssl.com" {:insecure? true}) + +;; By default we automatically follow 30* redirects... +(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org") -;; If you don't want to follow-redirects automatically: -(client/get "http://site.come/redirects-somewhere" {:follow-redirects false}) +;; ... but you don't have to +(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org" + {:follow-redirects false}) ;; Send form params as a urlencoded body -(client/post "http//site.com" {:form-params {:foo "bar"}}) +(client/post "https://httpbin.org/post" {:form-params {:foo "bar"}}) ;; Basic authentication -(client/get "http://site.com/protected" {:basic-auth ["user" "pass"]}) -(client/get "http://site.com/protected" {:basic-auth "user:pass"}) +(client/get "https://joe:cool@httpbin.org/basic-auth/joe/cool") +(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth ["joe" "cool"]}) +(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth "joe:cool"}) -;; Query parameters -(client/get "http://site.com/search" {:query-params {"q" "foo, bar"}}) +;; Query parameters can be specified as a map +(client/get "https://httpbin.org/get" {:query-params {"q" "foo, bar"}}) ``` -The client will also follow redirects on the appropriate `30*` status -codes. +The client transparently accepts and decompresses the `gzip` and `deflate` content encodings. -The client transparently accepts and decompresses the `gzip` and -`deflate` content encodings. +```Clojure +(client/get "https://httpbin.org/gzip") + +(client/get "https://httpbin.org/deflate") +``` ### Nested params Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatically flattened to `a[b]=1`. -We'll use `httpbin.org` to demonstrate: ```clojure -(-> (client/get "https://httpbin.org/get" +(-> (client/get "https://httpbin.org/get" {:query-params {:one {:two 2 :three 3}}}) :body println) @@ -130,50 +140,54 @@ We'll use `httpbin.org` to demonstrate: } ``` -### Input coercion +### Request body coercion ```clojure -;; body as a byte-array -(client/post "http://site.com/resources" {:body my-byte-array}) - -;; body as a string -(client/post "http://site.com/resources" {:body "string"}) - -;; :body-encoding is optional and defaults to "UTF-8" -(client/post "http://site.com/resources" - {:body "string" :body-encoding "UTF-8"}) - -;; body as a file -(client/post "http://site.com/resources" - {:body (clojure.java.io/file "/tmp/foo") :body-encoding - "UTF-8"}) - -;; :length is NOT optional for passing an InputStream in -(client/post "http://site.com/resources" - {:body (clojure.java.io/input-stream "/tmp/foo") - :length 1000}) +;; body as byte-array +(client/post "https://httbin.org/post" {:body (.getBytes "testing123")}) + +;; body from a string +(client/post "https://httpbin.org/post" {:body "testing456"}) + +;; string :body-encoding is optional and defaults to "UTF-8" +(client/post "https://httpbin.org/post" + {:body "mystring" :body-encoding "UTF-8"}) + +;; body from a file +(require '[clojure.java.io :as io]) +(spit "clj-http-lite-test.txt" "from a file") +(client/post "https://httpbin.org/post" + {:body (io/file "clj-http-lite-test.txt") + :body-encoding "UTF-8"}) + +;; from a stream +(with-open [is (io/input-stream "clj-http-lite-test.txt")] + (client/post "https://httpbin.org/post" + {:body (io/input-stream "clj-http-lite-test.txt")}) ) ``` -### Output coercion +### Output body coercion ```clojure -;; The default output is a string body -(client/get "http://site.com/foo.txt") +;; The default response body is a string body +(client/get "https://clojure.org") -;; Coerce as a byte-array -(client/get "http://site.com/favicon.ico" {:as :byte-array}) +;; Coerce to a byte-array +(client/get "http://clojure.org" {:as :byte-array}) -;; Coerce as something other than UTF-8 string -(client/get "http://site.com/string.txt" {:as "UTF-16"}) +;; Coerce to a string with using a specific charset, default is UTF-8 +(client/get "http://clojure.org" {:as "US-ASCII"}) -;; Try to automatically coerce the output based on the content-type -;; header (this is currently a BETA feature!) -(client/get "http://site.com/foo.bar" {:as :auto}) +;; Try to automatically coerce the body based on the content-type +;; response header charset +(client/get "https://google.com" {:as :auto}) ;; Return the body as a stream -(client/get "http://site.com/bigrequest.html" {:as :stream}) ;; Note that the connection to the server will NOT be closed until the ;; stream has been read +(let [res (client/get "https://clojure.org" {:as :stream})] + (with-open [body-stream (:body res)] + (slurp body-stream))) ``` A more general `request` function is also available, which is useful @@ -182,34 +196,36 @@ as a primitive for building higher-level interfaces: ```clojure (defn api-action [method path & [opts]] (client/request - (merge {:method method :url (str "http://site.com/" path)} opts))) + (merge {:method method :url (str "https://some.api/" path)} opts))) ``` ### Exceptions -The client will throw exceptions on, well, exceptional status -codes. clj-http will throw an `ex-info` with the response as `ex-data`. +The client will throw exceptions on, exceptional HTTP status +codes. Clj-http-lite throws an `ex-info` with the response as `ex-data`. ```clojure -user=> (client/get "http://site.com/broken") -Execution error (ExceptionInfo) at clj-http.lite.client/wrap-exceptions$fn (client.clj:38). -clj-http: status 404 -user=> (-> *e ex-data :status) -404 -user=> (-> *e ex-data keys) -(:headers :status :body) +(client/get "https://httpbin.org/404") +;; => ExceptionInfo clj-http: status 404 clojure.core/ex-info (core.clj:4617) + +(-> *e ex-data :status) +;; => 404 + +(-> *e ex-data keys) +;; => (:headers :status :body) ``` -You can also ignore exceptions and handle them yourself: +You can suppress HTTP status exceptions and handle them yourself: ``` clojure -(client/get "http://site.com/broken" {:throw-exceptions false}) +(client/get "https://httpbin.org/404" {:throw-exceptions false}) ``` Or ignore an unknown host (methods return 'nil' if this is set to true and the host does not exist: ``` clojure (client/get "http://aoeuntahuf89o.com" {:ignore-unknown-host? true}) +;; => nil ``` ### Proxies @@ -238,8 +254,8 @@ such), check out the ## Design -The design of `clj-http` is inspired by the -[Ring](http://github.com/mmcgrana/ring) protocol for Clojure HTTP +The design of `clj-http` (and therefore `clj-http-lite`) is inspired by the +[Ring](https://github.com/ring-clojure/ring) protocol for Clojure HTTP server applications. The client in `clj-http.lite.core` makes HTTP requests according to a given @@ -255,26 +271,32 @@ are sugar over this `clj-http.lite.client/request` function. To run tests for the JVM: - $ bb clean - $ bb deps +```shell +$ bb clean +$ bb deps - Run all Clojure tests against minimum supported version of Clojure (1.8) - $ clojure -M:test +Run all Clojure tests against minimum supported version of Clojure (1.8) +$ clojure -M:test - Run Clojure against a specific Clojure version, for example 1.11 - $ clojure -M:1.11:test +Run Clojure against a specific Clojure version, for example 1.11 +$ clojure -M:1.11:test +``` ### Babashka Tests To run a small suite of sanity tests for babashka (found under ./bb]): - $ bb test:bb +```shell +$ bb test:bb +``` ### Linting Our CI workflow lints sources with clj-kondo, and you can too! - $ bb lint +```shell +$ bb lint +``` ### Release From c7b4f7f81cbf87fa8277952c48bd6b8586e9b0ce Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 19 Aug 2022 22:05:12 -0400 Subject: [PATCH 108/143] Apply :insecure? ssl opt only to current request (#47) Was formerly also being applied to all subsequent requests. Includes a small work-around for bb compatibility. Closes #45 --- CHANGELOG.md | 3 +- bb/clj_http/lite/client_test.clj | 7 +++++ src/clj_http/lite/core.clj | 50 +++++++++++++++++--------------- test/clj_http/test/core_test.clj | 5 +++- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c759d0..15126859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ - If specified, request's body encoding is now applied, else defaults to UTF-8 ([#18](https://github.com/clj-commons/clj-http-lite/issues/18)) ([@lread](https://github.com/lread)) - User info from request URL now applied to basic auth ([#34](https://github.com/clj-commons/clj-http-lite/issues/34)) ([@lread](https://github.com/lread)) - Nested query and form parameters are now automatically flattened ([#43](https://github.com/clj-commons/clj-http-lite/issues/43)) ([@lread](https://github.com/lread)) +- The `:insecure?` option is now applied only to the current request ([#45](https://github.com/clj-commons/clj-http-lite/issues/45)) ([@lread](https://github.com/lread)) - Quality - - Docstrings reviewed and updated + - Docstrings and README reviewed and updated - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) ### 0.4.384 diff --git a/bb/clj_http/lite/client_test.clj b/bb/clj_http/lite/client_test.clj index 3a0055ba..821ef55f 100644 --- a/bb/clj_http/lite/client_test.clj +++ b/bb/clj_http/lite/client_test.clj @@ -29,3 +29,10 @@ (is false "should not reach here") (catch Exception e (is (:headers (ex-data e)))))) + +(deftest insecure-test + (is (thrown? Exception + (client/get "https://expired.badssl.com"))) + (is (= 200 (:status (client/get "https://expired.badssl.com" {:insecure? true})))) + (is (thrown? Exception + (client/get "https://expired.badssl.com")))) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 03b5d919..98023a3e 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -41,35 +41,37 @@ (.flush baos) (.toByteArray baos))))) -(def ^:private insecure-mode - (delay (throw (ex-info "insecure? option not supported in this environment" - {})))) +(defn- trust-all-ssl! + [_conn] + (throw (ex-info "insecure? option not supported in this environment" + {}))) (defmacro ^:private def-insecure [] (when (try (import '[javax.net.ssl HttpsURLConnection SSLContext TrustManager X509TrustManager HostnameVerifier SSLSession]) (catch Exception _)) '(do - (defn- my-host-verifier [] - (proxy [HostnameVerifier] [] - (verify [^String hostname ^javax.net.ssl.SSLSession session] true))) - - (defn trust-invalid-manager - "This allows the ssl socket to connect with invalid/self-signed SSL certs." - [] - (reify javax.net.ssl.X509TrustManager - (getAcceptedIssuers [this] nil) - (checkClientTrusted [this certs authType]) - (checkServerTrusted [this certs authType]))) + (def ^:private trust-all-hostname-verifier + (delay + (proxy [HostnameVerifier] [] + (verify [^String hostname ^SSLSession session] true)))) - (def ^:private insecure-mode + (def ^:private trust-all-ssl-socket-factory (delay - (HttpsURLConnection/setDefaultSSLSocketFactory - (.getSocketFactory - (doto (SSLContext/getInstance "SSL") - (.init nil (into-array TrustManager [(trust-invalid-manager)]) - (new java.security.SecureRandom))))) - (HttpsURLConnection/setDefaultHostnameVerifier (my-host-verifier))))))) + (.getSocketFactory + (doto (SSLContext/getInstance "SSL") + (.init nil (into-array TrustManager [(reify X509TrustManager + (getAcceptedIssuers [this] nil) + (checkClientTrusted [this certs authType]) + (checkServerTrusted [this certs authType]))]) + (new java.security.SecureRandom)))))) + + (defn- trust-all-ssl! + [conn] + (when (instance? HttpsURLConnection conn) + (let [^HttpsURLConnection ssl-conn conn] + (.setHostnameVerifier ssl-conn @trust-all-hostname-verifier) + (.setSSLSocketFactory ssl-conn @trust-all-ssl-socket-factory))))))) (def-insecure) @@ -84,9 +86,9 @@ (when server-port (str ":" server-port)) uri (when query-string (str "?" query-string))) - _ (when insecure? - @insecure-mode) ^HttpURLConnection conn (.openConnection (URL. http-url))] + (when insecure? + (trust-all-ssl! conn)) (when (and content-type character-encoding) (.setRequestProperty conn "Content-Type" (str content-type "; charset=" @@ -116,4 +118,4 @@ (coerce-body-entity req conn))} (when save-request? {:request (assoc (dissoc req :save-request?) - :http-url http-url)})))) + :http-url http-url)})))) diff --git a/test/clj_http/test/core_test.clj b/test/clj_http/test/core_test.clj index 47d7cd1f..f87929e9 100644 --- a/test/clj_http/test/core_test.clj +++ b/test/clj_http/test/core_test.clj @@ -172,7 +172,10 @@ (request client-opts))) (let [resp (request (assoc client-opts :insecure? true))] (is (= 200 (:status resp))) - (is (= "get" (slurp-body resp)))))) + (is (= "get" (slurp-body resp)))) + (is (thrown? javax.net.ssl.SSLException + (request client-opts)) + "subsequent bad cert fetch throws"))) (deftest ^{:integration true} t-save-request-obj (let [resp (request {:request-method :post :uri "/post" From 0219dc9421547d49fa615564a3706f514cd51538 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sat, 20 Aug 2022 12:12:48 -0400 Subject: [PATCH 109/143] Turf conditional insecure? option support (#50) Babashka now includes all necessary classes to support the insecure? option. Closes #49 --- src/clj_http/lite/core.clj | 53 +++++++++++++++----------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/src/clj_http/lite/core.clj b/src/clj_http/lite/core.clj index 98023a3e..dea6c41c 100644 --- a/src/clj_http/lite/core.clj +++ b/src/clj_http/lite/core.clj @@ -2,7 +2,8 @@ "Core HTTP request/response implementation." (:require [clojure.java.io :as io]) (:import (java.io ByteArrayOutputStream InputStream) - (java.net URL HttpURLConnection))) + (java.net HttpURLConnection URL) + (javax.net.ssl HostnameVerifier HttpsURLConnection SSLContext SSLSession TrustManager X509TrustManager))) (set! *warn-on-reflection* true) @@ -41,39 +42,27 @@ (.flush baos) (.toByteArray baos))))) -(defn- trust-all-ssl! - [_conn] - (throw (ex-info "insecure? option not supported in this environment" - {}))) - -(defmacro ^:private def-insecure [] - (when (try (import '[javax.net.ssl - HttpsURLConnection SSLContext TrustManager X509TrustManager HostnameVerifier SSLSession]) - (catch Exception _)) - '(do - (def ^:private trust-all-hostname-verifier - (delay - (proxy [HostnameVerifier] [] - (verify [^String hostname ^SSLSession session] true)))) - - (def ^:private trust-all-ssl-socket-factory - (delay - (.getSocketFactory - (doto (SSLContext/getInstance "SSL") - (.init nil (into-array TrustManager [(reify X509TrustManager - (getAcceptedIssuers [this] nil) - (checkClientTrusted [this certs authType]) - (checkServerTrusted [this certs authType]))]) - (new java.security.SecureRandom)))))) +(def ^:private trust-all-hostname-verifier + (delay + (proxy [HostnameVerifier] [] + (verify [^String hostname ^SSLSession session] true)))) - (defn- trust-all-ssl! - [conn] - (when (instance? HttpsURLConnection conn) - (let [^HttpsURLConnection ssl-conn conn] - (.setHostnameVerifier ssl-conn @trust-all-hostname-verifier) - (.setSSLSocketFactory ssl-conn @trust-all-ssl-socket-factory))))))) +(def ^:private trust-all-ssl-socket-factory + (delay + (.getSocketFactory + (doto (SSLContext/getInstance "SSL") + (.init nil (into-array TrustManager [(reify X509TrustManager + (getAcceptedIssuers [_this] nil) + (checkClientTrusted [_this _certs _authType]) + (checkServerTrusted [_this _certs _authType]))]) + (new java.security.SecureRandom)))))) -(def-insecure) +(defn- trust-all-ssl! + [conn] + (when (instance? HttpsURLConnection conn) + (let [^HttpsURLConnection ssl-conn conn] + (.setHostnameVerifier ssl-conn @trust-all-hostname-verifier) + (.setSSLSocketFactory ssl-conn @trust-all-ssl-socket-factory)))) (defn request "Executes the HTTP request corresponding to the given Ring `req` map and From 58a8b3f0beeb1fbc52159a91057f3720512ac428 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 22 Aug 2022 13:43:13 -0400 Subject: [PATCH 110/143] tests: server-name no longer includes port (#53) Closes #52 --- test/clj_http/test/core_test.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/clj_http/test/core_test.clj b/test/clj_http/test/core_test.clj index f87929e9..4851c2e6 100644 --- a/test/clj_http/test/core_test.clj +++ b/test/clj_http/test/core_test.clj @@ -82,8 +82,8 @@ (defn base-req [] {:scheme :http - :server-name (str "localhost:" (current-port)) - :port (current-port)}) + :server-name "localhost" + :server-port (current-port)}) (defn request [req] (core/request (merge (base-req) req))) @@ -166,8 +166,8 @@ (let [client-opts {:request-method :get :uri "/get" :scheme :https - :server-name (str "localhost:" (current-https-port)) - :port (current-https-port)}] + :server-name "localhost" + :server-port (current-https-port)}] (is (thrown? javax.net.ssl.SSLException (request client-opts))) (let [resp (request (assoc client-opts :insecure? true))] @@ -186,8 +186,8 @@ :http-url (str "http://localhost:" (current-port) "/post") :request-method :post :uri "/post" - :server-name (str "localhost:" (current-port)) - :port (current-port)} + :server-name "localhost" + :server-port (current-port)} (-> resp :request (dissoc :body)))))) From 1e64a91f9b8e381bfe276c9381dc2b22fe19e44c Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 22 Aug 2022 14:23:24 -0400 Subject: [PATCH 111/143] tests: finish moving to conventional nses (#54) Addendum to #35 --- test/clj_http/{test => lite}/client_test.clj | 4 ++-- test/clj_http/{test => lite}/core_test.clj | 2 +- test/clj_http/{test => lite}/links_test.clj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename test/clj_http/{test => lite}/client_test.clj (99%) rename test/clj_http/{test => lite}/core_test.clj (99%) rename test/clj_http/{test => lite}/links_test.clj (98%) diff --git a/test/clj_http/test/client_test.clj b/test/clj_http/lite/client_test.clj similarity index 99% rename from test/clj_http/test/client_test.clj rename to test/clj_http/lite/client_test.clj index c62b6d85..e43426cd 100644 --- a/test/clj_http/test/client_test.clj +++ b/test/clj_http/lite/client_test.clj @@ -1,6 +1,6 @@ -(ns clj-http.test.client-test +(ns clj-http.lite.client-test (:require [clj-http.lite.client :as client] - [clj-http.test.core-test :refer [base-req with-server current-port]] + [clj-http.lite.core-test :refer [base-req with-server current-port]] [clj-http.lite.util :as util] [clojure.test :refer [deftest is testing use-fixtures]]) (:import (java.net UnknownHostException))) diff --git a/test/clj_http/test/core_test.clj b/test/clj_http/lite/core_test.clj similarity index 99% rename from test/clj_http/test/core_test.clj rename to test/clj_http/lite/core_test.clj index 4851c2e6..b0960520 100644 --- a/test/clj_http/test/core_test.clj +++ b/test/clj_http/lite/core_test.clj @@ -1,4 +1,4 @@ -(ns clj-http.test.core-test +(ns clj-http.lite.core-test (:require [clj-http.lite.core :as core] [clj-http.lite.util :as util] [clojure.test :refer [deftest is use-fixtures]] diff --git a/test/clj_http/test/links_test.clj b/test/clj_http/lite/links_test.clj similarity index 98% rename from test/clj_http/test/links_test.clj rename to test/clj_http/lite/links_test.clj index f9128cf8..a9ac61a9 100644 --- a/test/clj_http/test/links_test.clj +++ b/test/clj_http/lite/links_test.clj @@ -1,4 +1,4 @@ -(ns clj-http.test.links-test +(ns clj-http.lite.links-test "Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/test/clj_http/test/links_test.clj" (:require [clj-http.lite.links :refer [wrap-links]] [clojure.test :refer [deftest is testing]])) From b51aff055e9f54e980afc67f5bc02e7fc9837df6 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 22 Aug 2022 16:40:56 -0400 Subject: [PATCH 112/143] docs: rework graal vm native image tip [skip ci] (#55) Be more vague and point to Graal docs. A "known issue" implies a bug, rename to "tip". --- README.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e37b2507..45478444 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with Babashka and GraalVM. -> This is a clj-commons maintained fork of the original [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. +> This is a clj-commons maintained fork of the archived [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. -[Installation](#installation) | [Usage](#usage) | [Known Issues](#known-issues) | [Design](#design) | [Development](#development) +[Installation](#installation) | [Usage](#usage) | [Design](#design) | [Development](#development) ## Installation @@ -240,17 +240,11 @@ If you need to fake clj-http responses (for things like testing and such), check out the [clj-http-fake](https://github.com/myfreeweb/clj-http-fake) library. -## Known Issues +## GraalVM Native Image Tips -- If you issue HTTPS connections, [Native Image](https://www.graalvm.org/docs/reference-manual/native-image/) compilation requires an additional parameter in order to enable its support in the generated image. +You'll need to enable url protocols when building your native image. - If you get the following kind of error: - - Exception in thread "main" java.net.MalformedURLException: Accessing an URL protocol that was not enabled. - The URL protocol https is supported but not enabled by default. It must be enabled by adding the - -H:EnableURLProtocols=https option to the native-image command. - - Then add either `-H:EnableURLProtocols=https` or `--enable-https` option to your compilation step. +See [GraalVM docs](https://www.graalvm.org/22.2/reference-manual/native-image/dynamic-features/URLProtocols/). ## Design From db63f7e9796d7054894c81a3cae8ee25f3fffad7 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 22 Aug 2022 17:03:48 -0400 Subject: [PATCH 113/143] test refactor: group all integration tests (#56) All integration share same test fixture setup, so it makes sense to have them together. No need for ^integration metadata on tests any more, they are grouped by namespace now. --- test/clj_http/lite/client_test.clj | 52 +---------- .../{core_test.clj => integration_test.clj} | 90 +++++++++++++++---- 2 files changed, 73 insertions(+), 69 deletions(-) rename test/clj_http/lite/{core_test.clj => integration_test.clj} (68%) diff --git a/test/clj_http/lite/client_test.clj b/test/clj_http/lite/client_test.clj index e43426cd..8eb1f50c 100644 --- a/test/clj_http/lite/client_test.clj +++ b/test/clj_http/lite/client_test.clj @@ -1,59 +1,9 @@ (ns clj-http.lite.client-test (:require [clj-http.lite.client :as client] - [clj-http.lite.core-test :refer [base-req with-server current-port]] [clj-http.lite.util :as util] - [clojure.test :refer [deftest is testing use-fixtures]]) + [clojure.test :refer [deftest is testing]]) (:import (java.net UnknownHostException))) -(use-fixtures :each with-server) - -(deftest ^{:integration true} roundtrip - ;; roundtrip with scheme as a keyword - (let [resp (client/request (merge (base-req) {:uri "/get" :method :get}))] - (is (= 200 (:status resp))) - (is (= "get" (:body resp)))) - ;; roundtrip with scheme as a string - (let [resp (client/request (merge (base-req) {:uri "/get" - :method :get - :scheme "http"}))] - (is (= 200 (:status resp))) - (is (= "get" (:body resp))))) - -(deftest ^{:integration true} basic-auth-no-creds - (let [resp (client/request (merge (base-req) {:method :get - :uri "/basic-auth" - :throw-exceptions false}))] - (is (= 401 (:status resp))) - (is (= "denied" (:body resp))))) - -(deftest ^{:integration true} basic-auth-bad-creds - (let [resp (client/request (merge (base-req) {:method :get - :uri "/basic-auth" - :throw-exceptions false - :basic-auth "username:nope"}))] - (is (= 401 (:status resp))) - (is (= "denied" (:body resp))))) - -(deftest ^{:integration true} basic-auth-creds-as-basic-auth - (let [resp (client/request (merge (base-req) {:method :get - :uri "/basic-auth" - :basic-auth "username:password"}))] - (is (= 200 (:status resp))) - (is (= "welcome" (:body resp))))) - -(deftest ^{:integration true} basic-auth-creds-as-user-info - (let [resp (client/request (merge (base-req) {:method :get - :uri "/basic-auth" - :user-info "username:password"}))] - (is (= 200 (:status resp))) - (is (= "welcome" (:body resp))))) - -(deftest ^{:integration true} basic-auth-creds-from-url - (let [resp (client/request {:method :get - :url (format "http://username:password@localhost:%d/basic-auth" (current-port))})] - (is (= 200 (:status resp))) - (is (= "welcome" (:body resp))))) - (defn is-passed [middleware req] (let [client (middleware identity)] (is (= req (client req))))) diff --git a/test/clj_http/lite/core_test.clj b/test/clj_http/lite/integration_test.clj similarity index 68% rename from test/clj_http/lite/core_test.clj rename to test/clj_http/lite/integration_test.clj index b0960520..2ff95d37 100644 --- a/test/clj_http/lite/core_test.clj +++ b/test/clj_http/lite/integration_test.clj @@ -1,5 +1,6 @@ -(ns clj-http.lite.core-test - (:require [clj-http.lite.core :as core] +(ns clj-http.lite.integration-test + (:require [clj-http.lite.client :as client] + [clj-http.lite.core :as core] [clj-http.lite.util :as util] [clojure.test :refer [deftest is use-fixtures]] [clojure.string :as str] @@ -91,55 +92,58 @@ (defn slurp-body [req] (slurp (:body req))) -(deftest ^{:integration true} makes-get-request +;; +;; Lower level internal unwrapped core requests +;; +(deftest makes-get-request (let [resp (request {:request-method :get :uri "/get"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp))))) -(deftest ^{:integration true} makes-head-request +(deftest makes-head-request (let [resp (request {:request-method :head :uri "/head"})] (is (= 200 (:status resp))) (is (nil? (:body resp))))) -(deftest ^{:integration true} sets-content-type-with-charset +(deftest sets-content-type-with-charset (let [resp (request {:request-method :get :uri "/content-type" :content-type "text/plain" :character-encoding "UTF-8"})] (is (= "text/plain; charset=UTF-8" (slurp-body resp))))) -(deftest ^{:integration true} sets-content-type-without-charset +(deftest sets-content-type-without-charset (let [resp (request {:request-method :get :uri "/content-type" :content-type "text/plain"})] (is (= "text/plain" (slurp-body resp))))) -(deftest ^{:integration true} sets-arbitrary-headers +(deftest sets-arbitrary-headers (let [resp (request {:request-method :get :uri "/header" :headers {"X-My-Header" "header-val"}})] (is (= "header-val" (slurp-body resp))))) -(deftest ^{:integration true} sends-and-returns-byte-array-body +(deftest sends-and-returns-byte-array-body (let [resp (request {:request-method :post :uri "/post" :body (util/utf8-bytes "contents")})] (is (= 200 (:status resp))) (is (= "contents" (slurp-body resp))))) -(deftest ^{:integration true} returns-arbitrary-headers +(deftest returns-arbitrary-headers (let [resp (request {:request-method :get :uri "/get"})] (is (string? (get-in resp [:headers "date"]))))) -(deftest ^{:integration true} returns-status-on-exceptional-responses +(deftest returns-status-on-exceptional-responses (let [resp (request {:request-method :get :uri "/error"})] (is (= 500 (:status resp))))) -(deftest ^{:integration true} returns-status-on-redirect +(deftest returns-status-on-redirect (let [resp (request {:request-method :get :uri "/redirect" :follow-redirects false})] (is (= 302 (:status resp))))) -(deftest ^{:integration true} auto-follows-on-redirect +(deftest auto-follows-on-redirect (let [resp (request {:request-method :get :uri "/redirect"})] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp))))) -(deftest ^{:integration true} sets-conn-timeout +(deftest sets-conn-timeout ;; indirect way of testing if a connection timeout will fail by passing in an ;; invalid argument (try @@ -148,7 +152,7 @@ (catch Exception e (is (= IllegalArgumentException (class e)))))) -(deftest ^{:integration true} sets-socket-timeout +(deftest sets-socket-timeout (try (request {:request-method :get :uri "/timeout" :socket-timeout 1}) (throw (Exception. "Shouldn't get here.")) @@ -156,13 +160,13 @@ (is (or (= java.net.SocketTimeoutException (class e)) (= java.net.SocketTimeoutException (class (.getCause e)))))))) -(deftest ^{:integration true} delete-with-body +(deftest delete-with-body (let [resp (request {:request-method :delete :uri "/delete-with-body" :body (.getBytes "foo bar")})] (is (= 200 (:status resp))) (is (= "delete-with-body" (slurp-body resp))))) -(deftest ^{:integration true} self-signed-ssl-get +(deftest self-signed-ssl-get (let [client-opts {:request-method :get :uri "/get" :scheme :https @@ -177,7 +181,7 @@ (request client-opts)) "subsequent bad cert fetch throws"))) -(deftest ^{:integration true} t-save-request-obj +(deftest t-save-request-obj (let [resp (request {:request-method :post :uri "/post" :body (.getBytes "foo bar" "UTF-8") :save-request? true})] @@ -192,7 +196,57 @@ :request (dissoc :body)))))) -(deftest ^{:integration true} t-streaming-response +(deftest t-streaming-response (let [stream (:body (request {:request-method :get :uri "/get" :as :stream})) body (slurp stream)] (is (= "get" body)))) + +;; +;; API level client wrapped requests +;; +(deftest roundtrip + ;; roundtrip with scheme as a keyword + (let [resp (client/request (merge (base-req) {:uri "/get" :method :get}))] + (is (= 200 (:status resp))) + (is (= "get" (:body resp)))) + ;; roundtrip with scheme as a string + (let [resp (client/request (merge (base-req) {:uri "/get" + :method :get + :scheme "http"}))] + (is (= 200 (:status resp))) + (is (= "get" (:body resp))))) + +(deftest basic-auth-no-creds + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :throw-exceptions false}))] + (is (= 401 (:status resp))) + (is (= "denied" (:body resp))))) + +(deftest basic-auth-bad-creds + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :throw-exceptions false + :basic-auth "username:nope"}))] + (is (= 401 (:status resp))) + (is (= "denied" (:body resp))))) + +(deftest basic-auth-creds-as-basic-auth + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :basic-auth "username:password"}))] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) + +(deftest basic-auth-creds-as-user-info + (let [resp (client/request (merge (base-req) {:method :get + :uri "/basic-auth" + :user-info "username:password"}))] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) + +(deftest basic-auth-creds-from-url + (let [resp (client/request {:method :get + :url (format "http://username:password@localhost:%d/basic-auth" (current-port))})] + (is (= 200 (:status resp))) + (is (= "welcome" (:body resp))))) From 392e7004153193c0bae3d1572ee6639639ca59da Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Tue, 23 Aug 2022 13:48:20 +0200 Subject: [PATCH 114/143] Add example of mocking using with-redefs (#57) [skip ci] Resolves #51 Signed-off-by: Anders Eknert --- .gitignore | 2 ++ README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 51c74c0e..a643f88c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ aws.clj /.lein-deps-sum .cache .cpcache +.idea +*.iml diff --git a/README.md b/README.md index 45478444..76e91e39 100644 --- a/README.md +++ b/README.md @@ -234,11 +234,63 @@ A proxy can be specified by setting the Java properties: `.proxyHost` and `.proxyPort` where `` is the client scheme used (normally 'http' or 'https'). -## Faking clj-http responses +## Mocking clj-http responses -If you need to fake clj-http responses (for things like testing and -such), check out the -[clj-http-fake](https://github.com/myfreeweb/clj-http-fake) library. +Mocking responses from the clj-http-lite client in tests is easily accomplished with e.g. `with-redefs`: + +```clojure +(defn my-http-function [] + (let [response (client/get "https://example.org")] + (when (= 200 (:status response)) + (:body response)))) + +(deftest my-http-function-test + (with-redefs [client/get (fn [_] {:status 200 :headers {"content-type" "text/plain"} :body "OK"})] + (is (= (my-http-function) "OK")))) +``` + +More advanced mocking may be performed by matching attributes in the `request`, like the `mock-response` function below. + +```clojure +(ns http-test + (:require [clojure.data.json :as json] + [clojure.test :refer [deftest is testing]] + [clj-http.lite.client :as client])) + +(defn send-report [data] + (:body (client/post "https://example.com/reports" {:body data}))) + +(defn get-users [] + (json/read-str (:body (client/get "https://example.com/users")))) + +(defn get-admin [] + (let [response (client/get "https://example.com/admin")] + (if (= 200 (:status response)) + (:body response) + "403 Forbidden"))) + +(defn mock-response [{:keys [url method body] :as request}] + (condp = [url method] + ["https://example.com/reports" :post] + {:status 201 :headers {"content-type" "text/plain"} :body (str "created: " body)} + + ["https://example.com/users" :get] + {:status 200 :headers {"content-type" "application/json"} :body (json/write-str ["joe" "jane" "bob"])} + + ["https://example.com/admin" :get] + {:status 403 :headers {"content-type" "text/plain"} :body "forbidden"} + + (throw (ex-info "unexpected request" request)))) + +(deftest send-report-test + (with-redefs [client/request mock-response] + (testing "sending report" + (is (= (send-report {:balance 100}) "created: {:balance 100}"))) + (testing "list users" + (is (= (get-users) ["joe" "jane" "bob"]))) + (testing "access admin page" + (is (= (get-admin) "403 Forbidden"))))) +``` ## GraalVM Native Image Tips From 6c128fdee7f773335c799ab4298cf072442610e4 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 23 Aug 2022 15:45:59 -0400 Subject: [PATCH 115/143] Run entire test suite under Babashka (#58) We were formerly running a small sanity test for babashka. By separating out our test http server to a process, we can now hit our full suite with babashka. We've kept our bb sanity tests but moved them under our full suite. (see client-sanity-test ns). Bb task `test:bb` now runs the full suite. For consistency, I've re-added `test:jvm` which behaves the same as `test:bb` but also supports a `--clj-version` option. CI has been updated to use/exercise the test:jvm task. Also added a simple test reporter for better feedback when testing and to make it abundantly clear which platform we are testing on. See update README for usage. Some tests initially failed under bb: - Tests were checking specifically for thrown `java.net.ssl.SSLException` and `java.net.SocketTimeoutException`. Neither of these classes are currently available in bb. I switched to checking the message only. - Encoding tests were testing against "windows-1252" charset. Bb does include this charset, but on Windows only. I switched the test to use "iso-8859-1" which is available on bb on all platforms. Other notes: - noticed that the timeout test sometimes very rarely did not timeout; I increased the server-side timeout to hopefully force the expected failure. - GitHub Actions on Windows can be very slow. Bumped wait time for our http-server process startup to a very generous 2 mins and added some logging so that we can witness how long this typically takes. Closes #48 --- .github/workflows/ci.yml | 13 +-- README.md | 27 +++-- bb.edn | 16 ++- bb/clj_http/lite/test_runner.clj | 10 -- bb/test_jvm.clj | 42 +++++++ deps.edn | 11 +- .../clj_http/lite/client_sanity_test.clj | 11 +- test/clj_http/lite/client_test.clj | 7 +- test/clj_http/lite/integration_test.clj | 110 +++++------------- test/clj_http/lite/links_test.clj | 1 + test/clj_http/lite/test_util/http_server.clj | 81 +++++++++++++ .../lite/test_util/server_process.clj | 74 ++++++++++++ test/clj_http/lite/test_util/server_state.clj | 4 + test/clj_http/lite/test_util/test_report.clj | 11 ++ 14 files changed, 295 insertions(+), 123 deletions(-) delete mode 100644 bb/clj_http/lite/test_runner.clj create mode 100644 bb/test_jvm.clj rename bb/clj_http/lite/client_test.clj => test/clj_http/lite/client_sanity_test.clj (83%) create mode 100644 test/clj_http/lite/test_util/http_server.clj create mode 100644 test/clj_http/lite/test_util/server_process.clj create mode 100644 test/clj_http/lite/test_util/server_state.clj create mode 100644 test/clj_http/lite/test_util/test_report.clj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50ab3fa3..6d6430e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: - name: Lint run: bb lint - test: + test-jvm: runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false @@ -78,14 +78,11 @@ jobs: uses: DeLaGuardo/setup-clojure@9.4 with: bb: 'latest' - cli: 'latest' - name: Tools versions run: | echo "bb --version" bb --version - echo "clojure --version" - clojure --version echo "java -version" java -version @@ -93,9 +90,9 @@ jobs: run: bb deps - name: Run tests - run: clojure -M:${{ matrix.clojure-version }}:test + run: bb test:jvm --clj-version ${{ matrix.clojure-version }} - bb-test: + test-bb: runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false @@ -143,8 +140,8 @@ jobs: runs-on: ubuntu-latest needs: - lint - - test - - bb-test + - test-jvm + - test-bb steps: - name: Checkout diff --git a/README.md b/README.md index 76e91e39..3fdaa23b 100644 --- a/README.md +++ b/README.md @@ -315,26 +315,39 @@ are sugar over this `clj-http.lite.client/request` function. ### Clojure JVM Tests -To run tests for the JVM: - +Optionally: ```shell $ bb clean $ bb deps +``` + +Run all Clojure tests against minimum supported version of Clojure (1.8): -Run all Clojure tests against minimum supported version of Clojure (1.8) -$ clojure -M:test +```shell +$ bb test:jvm +``` -Run Clojure against a specific Clojure version, for example 1.11 -$ clojure -M:1.11:test +Run tests against a specific Clojure version, for example 1.11 +```shell +$ bb test:jvm --clj-version 1.11 +``` + +You can also include cognitect test runner options: +```shell +$ bb test:jvm --clj-version 1.9 --namespace-regex '*.sanity.*' ``` ### Babashka Tests -To run a small suite of sanity tests for babashka (found under ./bb]): +To run the entire test suite under Babashka: ```shell $ bb test:bb ``` +You can also include cognitect test runner options: +```shell +$ bb test:bb --var clj-http.lite.integration-test/roundtrip +``` ### Linting diff --git a/bb.edn b/bb.edn index 6c5bcc0c..4bc67afa 100644 --- a/bb.edn +++ b/bb.edn @@ -1,6 +1,5 @@ {:paths ["." "bb"] - :deps {org.clj-commons/clj-http-lite {:local/root "."} - lread/status-line {:git/url "https://github.com/lread/status-line.git" + :deps {lread/status-line {:git/url "https://github.com/lread/status-line.git" :sha "35ed39645038e81b42cb15ed6753b8462e60a06d"}} :tasks {:requires ([tasks :as t]) @@ -10,9 +9,18 @@ clean {:doc "Delete any work dirs" :task (clojure "-T:build clean")} + test:jvm + {:doc "Runs tests under JVM Clojure [--clj-version] (recognizes cognitect test-runner args)" + :task test-jvm/-main} test:bb - {:doc "Run babashka tests" - :task clj-http.lite.test-runner/-main} + {:doc "Runs tests under babashka Clojure (recognizes cognitect test-runner args)" + :extra-paths ["src" "test" "test-resources"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.1" :git/sha "dfb30dd"} + org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace" + :git/sha "16b8c53174a5c9d89d6e0ce4128aa30b071aabdf"}} + :requires ([cognitect.test-runner :as tr]) + :task (apply tr/-main *command-line-args*)} lint {:doc "[--rebuild] Lint source code" :task lint/-main} diff --git a/bb/clj_http/lite/test_runner.clj b/bb/clj_http/lite/test_runner.clj deleted file mode 100644 index b793c578..00000000 --- a/bb/clj_http/lite/test_runner.clj +++ /dev/null @@ -1,10 +0,0 @@ -(ns clj-http.lite.test-runner - (:require [clj-http.lite.client-test] - [clojure.test :as t])) - -(defn -main [& _] - (let [{:keys [fail error]} (t/run-tests 'clj-http.lite.client-test)] - (System/exit (if (or (pos? fail) - (pos? error)) - 1 0)))) - diff --git a/bb/test_jvm.clj b/bb/test_jvm.clj new file mode 100644 index 00000000..b66bbfa7 --- /dev/null +++ b/bb/test_jvm.clj @@ -0,0 +1,42 @@ +(ns test-jvm + (:require [babashka.cli :as cli] + [babashka.tasks :as t] + [lread.status-line :as status])) + +(defn -main [& args] + (let [valid-clojure-versions ["1.8" "1.9" "1.10" "1.11"] + spec {:clj-version + {:ref "" + :desc "The Clojure version to test against." + :coerce :string + :default-desc "1.8" + ;; don't specify :default, we want to know if the user passed this option in + :validate + {:pred (set valid-clojure-versions) + :ex-msg (fn [_m] + (str "--clj-version must be one of: " valid-clojure-versions))}}} + opts (cli/parse-opts args {:spec spec}) + clj-version (:clj-version opts) + runner-args (if-not clj-version + args + (loop [args args + out-args []] + (if-let [a (first args)] + (if (re-matches #"(--|:)clj-version" a) + (recur (drop 2 args) out-args) + (recur (rest args) (conj out-args a))) + out-args))) + clj-version (or clj-version "1.8")] + + (if (:help opts) + (do + (status/line :head "bb task option help") + (println (cli/format-opts {:spec spec})) + (status/line :head "test-runner option help") + (t/clojure "-M:test --test-help")) + (do + (println "Testing against Clojure" clj-version) + (apply t/clojure (format "-M:%s:test" clj-version) runner-args))))) + +(when (= *file* (System/getProperty "babashka.file")) + (apply -main *command-line-args*)) diff --git a/deps.edn b/deps.edn index 61113769..9683d21f 100644 --- a/deps.edn +++ b/deps.edn @@ -9,16 +9,21 @@ {:deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} slipset/deps-deploy {:mvn/version "0.2.0"}} :ns-default build} - :test + :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] - :extra-deps {io.github.cognitect-labs/test-runner - {:git/tag "v0.5.1" :git/sha "dfb30dd"} + :override-deps {org.clojure/clojure {:mvn/version "1.11.1"}} + :extra-deps {babashka/fs {:mvn/version "0.1.6"} ring/ring-jetty-adapter {:mvn/version "1.9.5"} ch.qos.logback/logback-classic {:mvn/version "1.2.11" :exclusions [org.slf4j/slf4j-api]} org.slf4j/jcl-over-slf4j {:mvn/version "1.7.36"} org.slf4j/jul-to-slf4j {:mvn/version "1.7.36"} org.slf4j/log4j-over-slf4j {:mvn/version "1.7.36"}} + :exec-fn clj-http.lite.test-util.http-server/run} + :test + {:extra-paths ["test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2022.08.03"}} diff --git a/bb/clj_http/lite/client_test.clj b/test/clj_http/lite/client_sanity_test.clj similarity index 83% rename from bb/clj_http/lite/client_test.clj rename to test/clj_http/lite/client_sanity_test.clj index 821ef55f..91dc2785 100644 --- a/bb/clj_http/lite/client_test.clj +++ b/test/clj_http/lite/client_sanity_test.clj @@ -1,6 +1,7 @@ -(ns clj-http.lite.client-test - (:require [cheshire.core :as json] - [clj-http.lite.client :as client] +(ns clj-http.lite.client-sanity-test + "A small subset of tests suitable for sanity testing. + Used by babashka libs tests." + (:require [clj-http.lite.client :as client] [clojure.test :as t :refer [deftest is]])) (deftest client-test @@ -11,14 +12,14 @@ (is (= 200 (:status (client/post "https://postman-echo.com/post" {:throw-exceptions false})))) (is (= 200 (:status (client/post "https://postman-echo.com/post" - {:body (json/generate-string {:a 1}) + {:body "{\"a\": 1}" :headers {"X-Hasura-Role" "admin"} :content-type :json :accept :json :throw-exceptions false})))) (is (= 200 (:status (client/put "https://postman-echo.com/put" - {:body (json/generate-string {:a 1}) + {:body "{\"a\": 1}" :headers {"X-Hasura-Role" "admin"} :content-type :json :accept :json diff --git a/test/clj_http/lite/client_test.clj b/test/clj_http/lite/client_test.clj index 8eb1f50c..05504aa8 100644 --- a/test/clj_http/lite/client_test.clj +++ b/test/clj_http/lite/client_test.clj @@ -1,6 +1,7 @@ (ns clj-http.lite.client-test (:require [clj-http.lite.client :as client] [clj-http.lite.util :as util] + [clj-http.lite.test-util.test-report] [clojure.test :refer [deftest is testing]]) (:import (java.net UnknownHostException))) @@ -132,8 +133,8 @@ (is (= "fooⓕⓞⓞ" (:body resp))))) (deftest apply-on-other-output-coercion - (let [client (fn [_req] {:body (.getBytes "sõme ßÒññÝ chÀråcters" "windows-1252") - :headers {"content-type" "text/foo;charset=windows-1252"}}) + (let [client (fn [_req] {:body (.getBytes "sõme ßÒññÝ chÀråcters" "ISO-8859-1") + :headers {"content-type" "text/foo;charset=ISO-8859-1"}}) o-client (client/wrap-output-coercion client) resp (o-client {:uri "/foo" :as :auto})] (is (= "sõme ßÒññÝ chÀråcters" (:body resp))))) @@ -153,7 +154,7 @@ (doseq [[in-body encoding expected-encoding] [["μτƒ8 нαs мαηλ ςнαяαςτεяs ൠ" nil "UTF-8"] ["μτƒ8 нαs мαηλ ςнαяαςτεяs ൠ" "UTF-8" "UTF-8"] ["plain text" "ASCII" "ASCII"] - ["sõme ßÒññÝ chÀråcters" "windows-1252" "windows-1252"]]] + ["sõme ßÒññÝ chÀråcters" "iso-8859-1" "iso-8859-1"]]] (let [resp (i-client {:body in-body :body-encoding encoding}) decoded-body (slurp (:body resp) :encoding expected-encoding)] (is (= expected-encoding (:character-encoding resp)) "character encoding") diff --git a/test/clj_http/lite/integration_test.clj b/test/clj_http/lite/integration_test.clj index 2ff95d37..5ae81150 100644 --- a/test/clj_http/lite/integration_test.clj +++ b/test/clj_http/lite/integration_test.clj @@ -2,89 +2,26 @@ (:require [clj-http.lite.client :as client] [clj-http.lite.core :as core] [clj-http.lite.util :as util] - [clojure.test :refer [deftest is use-fixtures]] - [clojure.string :as str] - [ring.adapter.jetty :as ring]) - (:import (org.eclipse.jetty.server Server ServerConnector) - (java.util Base64))) - -(set! *warn-on-reflection* true) - -(defn b64-decode [^String s] - (when s - (-> (Base64/getDecoder) - (.decode s) - util/utf8-string))) - -(defn handler [req] - (condp = [(:request-method req) (:uri req)] - [:get "/get"] - {:status 200 :body "get"} - [:head "/head"] - {:status 200} - [:get "/content-type"] - {:status 200 :body (:content-type req)} - [:get "/header"] - {:status 200 :body (get-in req [:headers "x-my-header"])} - [:post "/post"] - {:status 200 :body (slurp (:body req))} - [:get "/redirect"] {:status 302 :headers {"Location" "/get"}} - [:get "/error"] - {:status 500 :body "o noes"} - [:get "/timeout"] - (do - (Thread/sleep 10) - {:status 200 :body "timeout"}) - [:delete "/delete-with-body"] - {:status 200 :body "delete-with-body"} - ;; minimal to support testing - [:get "/basic-auth"] - (let [cred (some->> (get (:headers req) "authorization") - (re-find #"^Basic (.*)$") - last - b64-decode) - [user pass] (and cred (str/split cred #":"))] - (if (and (= "username" user) (= "password" pass)) - {:status 200 :body "welcome"} - {:status 401 :body "denied"})))) - -(defn make-server ^Server [] - (ring/run-jetty handler {:port 0 ;; Use a free port - :join? false - :ssl-port 0 ;; Use a free port - :ssl? true - :keystore "test-resources/keystore" - :key-password "keykey"})) + [clj-http.lite.test-util.server-process :as server-process] + [clj-http.lite.test-util.test-report] + [clojure.test :refer [deftest is use-fixtures]])) (def ^:dynamic *server* nil) -(defn- port-for-protocol [p] - (let [^Server s *server*] - (some (fn [^ServerConnector c] - (when (str/starts-with? (str/lower-case (.getDefaultProtocol c)) p) - (.getLocalPort c))) - (.getConnectors s)))) - -(defn current-port [] - (port-for-protocol "http/")) - -(defn current-https-port [] - (port-for-protocol "ssl")) - (defn with-server [t] - (let [s (make-server)] + (let [s (server-process/launch)] (try (binding [*server* s] (t)) (finally - (-> s .stop))))) + (server-process/kill s))))) -(use-fixtures :each with-server) +(use-fixtures :once with-server) (defn base-req [] {:scheme :http :server-name "localhost" - :server-port (current-port)}) + :server-port (:http-port *server*)}) (defn request [req] (core/request (merge (base-req) req))) @@ -155,10 +92,11 @@ (deftest sets-socket-timeout (try (request {:request-method :get :uri "/timeout" :socket-timeout 1}) - (throw (Exception. "Shouldn't get here.")) - (catch Exception e - (is (or (= java.net.SocketTimeoutException (class e)) - (= java.net.SocketTimeoutException (class (.getCause e)))))))) + (is false "expected a throw") + (catch Exception ^Exception e + (is (or (= "Read timed out" (.getMessage e)) + (let [^Exception cause (.getCause e)] + (= "Read timed out" (.getMessage cause)))))))) (deftest delete-with-body (let [resp (request {:request-method :delete :uri "/delete-with-body" @@ -171,15 +109,20 @@ :uri "/get" :scheme :https :server-name "localhost" - :server-port (current-https-port)}] - (is (thrown? javax.net.ssl.SSLException - (request client-opts))) + :server-port (:https-port *server*)}] + (try + (request client-opts) + (is false "expected a throw") + (catch Exception ^Exception e + (is (re-find #"SunCertPathBuilderException" (.getMessage e))))) (let [resp (request (assoc client-opts :insecure? true))] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp)))) - (is (thrown? javax.net.ssl.SSLException - (request client-opts)) - "subsequent bad cert fetch throws"))) + (try + (request client-opts) + (is false "expected a throw") + (catch Exception ^Exception e + (is (re-find #"SunCertPathBuilderException" (.getMessage e))))))) (deftest t-save-request-obj (let [resp (request {:request-method :post :uri "/post" @@ -187,11 +130,11 @@ :save-request? true})] (is (= 200 (:status resp))) (is (= {:scheme :http - :http-url (str "http://localhost:" (current-port) "/post") + :http-url (str "http://localhost:" (:http-port *server*) "/post") :request-method :post :uri "/post" :server-name "localhost" - :server-port (current-port)} + :server-port (:http-port *server*)} (-> resp :request (dissoc :body)))))) @@ -247,6 +190,7 @@ (deftest basic-auth-creds-from-url (let [resp (client/request {:method :get - :url (format "http://username:password@localhost:%d/basic-auth" (current-port))})] + :url (format "http://username:password@localhost:%d/basic-auth" + (:http-port *server*))})] (is (= 200 (:status resp))) (is (= "welcome" (:body resp))))) diff --git a/test/clj_http/lite/links_test.clj b/test/clj_http/lite/links_test.clj index a9ac61a9..d2d617c5 100644 --- a/test/clj_http/lite/links_test.clj +++ b/test/clj_http/lite/links_test.clj @@ -1,6 +1,7 @@ (ns clj-http.lite.links-test "Imported from https://github.com/dakrone/clj-http/blob/217393258e7863514debece4eb7b23a7a3fa8bd9/test/clj_http/test/links_test.clj" (:require [clj-http.lite.links :refer [wrap-links]] + [clj-http.lite.test-util.test-report] [clojure.test :refer [deftest is testing]])) (defn- link-handler [link-header] diff --git a/test/clj_http/lite/test_util/http_server.clj b/test/clj_http/lite/test_util/http_server.clj new file mode 100644 index 00000000..7f4b1b61 --- /dev/null +++ b/test/clj_http/lite/test_util/http_server.clj @@ -0,0 +1,81 @@ +(ns clj-http.lite.test-util.http-server + (:require [babashka.fs :as fs] + [clj-http.lite.util :as util] + [clj-http.lite.test-util.server-state :refer [server-state-file]] + [clojure.string :as str] + [ring.adapter.jetty :as ring]) + (:import (org.eclipse.jetty.server Server ServerConnector) + (java.util Base64))) + +(set! *warn-on-reflection* true) + +(defn b64-decode [^String s] + (when s + (-> (Base64/getDecoder) + (.decode s) + util/utf8-string))) + +(defn handler [req] + (condp = [(:request-method req) (:uri req)] + [:get "/get"] + {:status 200 :body "get"} + [:head "/head"] + {:status 200} + [:get "/content-type"] + {:status 200 :body (:content-type req)} + [:get "/header"] + {:status 200 :body (get-in req [:headers "x-my-header"])} + [:post "/post"] + {:status 200 :body (slurp (:body req))} + [:get "/redirect"] {:status 302 :headers {"Location" "/get"}} + [:get "/error"] + {:status 500 :body "o noes"} + [:get "/timeout"] + (do + (Thread/sleep 100) + {:status 200 :body "timeout"}) + [:delete "/delete-with-body"] + {:status 200 :body "delete-with-body"} + ;; minimal to support testing + [:get "/basic-auth"] + (let [cred (some->> (get (:headers req) "authorization") + (re-find #"^Basic (.*)$") + last + b64-decode) + [user pass] (and cred (str/split cred #":"))] + (if (and (= "username" user) (= "password" pass)) + {:status 200 :body "welcome"} + {:status 401 :body "denied"})) + [:get "/stop"] + (do + (future (Thread/sleep 1000) + (println "http-server exiting") + (System/exit 0)) + {:status 200 :body "bye"}))) + +(defn- port-for-protocol [^Server s p] + (some (fn [^ServerConnector c] + (when (str/starts-with? (str/lower-case (.getDefaultProtocol c)) p) + (.getLocalPort c))) + (.getConnectors s))) + +(defn run + "ex. clojure -X:http-server" + [_opts] + (let [^Server s (ring/run-jetty handler {:port 0 ;; Use a free port + :join? false + :ssl-port 0 ;; Use a free port + :ssl? true + :keystore "test-resources/keystore" + :key-password "keykey"})] + (println "server started") + (fs/create-dirs "target") + (let [ports {:http-port (port-for-protocol s "http/") + :https-port (port-for-protocol s "ssl")} + ;; write to temp then move to avoid chance of watcher reading partially written file + tmp-file (fs/create-temp-file {:path "target" + :prefix "http-server" + :suffix ".edn"})] + (spit (fs/file tmp-file) ports) + (fs/move tmp-file server-state-file {:atomic-move true + :replace-existing true})))) diff --git a/test/clj_http/lite/test_util/server_process.clj b/test/clj_http/lite/test_util/server_process.clj new file mode 100644 index 00000000..4db786e8 --- /dev/null +++ b/test/clj_http/lite/test_util/server_process.clj @@ -0,0 +1,74 @@ +(ns clj-http.lite.test-util.server-process + (:require [clj-http.lite.test-util.server-state :refer [server-state-file]] + [clojure.edn :as edn]) + (:import (java.net URL HttpURLConnection) + (java.lang ProcessBuilder$Redirect) + (java.time Duration))) + +(defn- url-reachable? [s] + (try + (let [^HttpURLConnection c (.openConnection (URL. s))] + (.setRequestMethod c "GET") + (= 200 (.getResponseCode c))) + (catch Throwable _e))) + +(defn kill [{:keys [^Process process http-port]}] + (when (and process (.isAlive process)) + (println "Stopping http-server") + (try + (let [^HttpURLConnection c (.openConnection (URL. (format "http://localhost:%d/stop" http-port)))] + (.setRequestMethod c "GET") + (.getResponseCode c)) + (catch Throwable e + (println "warn: stop command failed\n" (.printStackTrace e)))) + (.waitFor process))) + +(defn duration [start-ms end-ms] + (-> (Duration/ofMillis (- end-ms start-ms)) + str + (subs 2))) + +(defn launch [] + (when (.exists server-state-file) + (.delete server-state-file)) + (let [max-wait-msecs 120000 ;; Windows GitHub Actions CI can be painfully slow + status-every-ms 1000 + start-time-ms (System/currentTimeMillis) + time-limit-ms (+ start-time-ms max-wait-msecs) + ;; use bb's clojure launcher for an easy time on Windows + p (-> (ProcessBuilder. ["bb" "clojure" "-X:http-server"]) + (.redirectOutput ProcessBuilder$Redirect/INHERIT) + (.redirectError ProcessBuilder$Redirect/INHERIT) + (.start))] + (-> (Runtime/getRuntime) + (.addShutdownHook (Thread. (fn [] (when (.isAlive p) + (println "killing http-server forcibly") + (.destroyForcibly p) + (.waitFor p)))))) + (print "Starting http-server") + (flush) + (loop [next-status (System/currentTimeMillis) + server-state nil] + (cond + (not (.isAlive p)) + (throw (ex-info "Http-server process died unexpectedly" {})) + (> (System/currentTimeMillis) time-limit-ms) + (do (when server-state + (kill server-state)) + (throw (ex-info (format "Timed out after waiting %s for test http-server to start" + (duration start-time-ms (System/currentTimeMillis))) {}))) + (and server-state (url-reachable? (format "http://localhost:%d/get" + (:http-port server-state)))) + (do (println "waited" (duration start-time-ms (System/currentTimeMillis))) + server-state) + (and (not server-state) (.exists server-state-file)) + (recur next-status + (-> server-state-file slurp edn/read-string (assoc :process p))) + :else + (let [next-status (if (> (System/currentTimeMillis) next-status) + (do (print ".") + (flush) + (+ (System/currentTimeMillis) status-every-ms)) + next-status)] + (Thread/sleep 50) + (recur next-status server-state)))))) diff --git a/test/clj_http/lite/test_util/server_state.clj b/test/clj_http/lite/test_util/server_state.clj new file mode 100644 index 00000000..b46e6356 --- /dev/null +++ b/test/clj_http/lite/test_util/server_state.clj @@ -0,0 +1,4 @@ +(ns clj-http.lite.test-util.server-state + (:require [clojure.java.io :as io])) + +(def server-state-file (io/file "target/http-server.edn")) diff --git a/test/clj_http/lite/test_util/test_report.clj b/test/clj_http/lite/test_util/test_report.clj new file mode 100644 index 00000000..4b07367e --- /dev/null +++ b/test/clj_http/lite/test_util/test_report.clj @@ -0,0 +1,11 @@ +(ns clj-http.lite.test-util.test-report + (:require [clojure.test])) + +(def platform + (if (System/getProperty "babashka.version") + "bb" + (str "jvm-clj " (clojure-version)))) + +(defmethod clojure.test/report :begin-test-var [m] + (let [test-name (-> m :var meta :name)] + (println (format "=== %s [%s]" test-name platform)))) From 99ca49c7f1e3a13ba2d0ed7abaf2cd4638532473 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 23 Aug 2022 15:56:18 -0400 Subject: [PATCH 116/143] update changelog [skip ci] (#59) --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15126859..4513a095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,12 @@ - User info from request URL now applied to basic auth ([#34](https://github.com/clj-commons/clj-http-lite/issues/34)) ([@lread](https://github.com/lread)) - Nested query and form parameters are now automatically flattened ([#43](https://github.com/clj-commons/clj-http-lite/issues/43)) ([@lread](https://github.com/lread)) - The `:insecure?` option is now applied only to the current request ([#45](https://github.com/clj-commons/clj-http-lite/issues/45)) ([@lread](https://github.com/lread)) +- Docs + - Docstrings and README reviewed and updated ([@lread](https://github.com/lread)) + - Guidance on mocking HTTP requests now makes sense ([#51](https://github.com/clj-commons/clj-http-lite/issues/51)) (thanks [@anderseknert](https://github.com/anderseknert)!) - Quality - - Docstrings and README reviewed and updated - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) + - Babashka now exercised under full test suite ([#48](https://github.com/clj-commons/clj-http-lite/issues/48)) ([@lread](https://github.com/lread)) ### 0.4.384 From d7a46667e6dcddf4c8baf7d64cdc3f704f6583b7 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 25 Aug 2022 11:31:53 -0400 Subject: [PATCH 117/143] docs: add slack chat badge (#60) [skip ci] --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fdaa23b..b084c027 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# `clj-http-lite` [![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/clj-http-lite)](https://cljdoc.org/d/org.clj-commons/clj-http-lite) [![CI tests](https://github.com/clj-commons/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/clj-commons/clj-http-lite/actions) [![Clojars](https://img.shields.io/clojars/v/org.clj-commons/clj-http-lite.svg)](https://clojars.org/org.clj-commons/clj-http-lite) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) +# `clj-http-lite` +[![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/clj-http-lite)](https://cljdoc.org/d/org.clj-commons/clj-http-lite) [![CI tests](https://github.com/clj-commons/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/clj-commons/clj-http-lite/actions) [![Clojars](https://img.shields.io/clojars/v/org.clj-commons/clj-http-lite.svg)](https://clojars.org/org.clj-commons/clj-http-lite) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) [![Join chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://clojurians.slack.com/archives/C03UZ1Y8414) A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with Babashka and GraalVM. From 7c4809d621c3bf54b98401cf72c663da53cf6238 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 26 Aug 2022 12:29:55 -0400 Subject: [PATCH 118/143] docs: moved from md to adoc [skip ci] (#61) maintainer preference --- CHANGELOG.adoc | 35 +++++ CHANGELOG.md | 32 ----- README.md => README.adoc | 274 ++++++++++++++++++++++----------------- 3 files changed, 188 insertions(+), 153 deletions(-) create mode 100644 CHANGELOG.adoc delete mode 100644 CHANGELOG.md rename README.md => README.adoc (62%) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc new file mode 100644 index 00000000..16a2ca16 --- /dev/null +++ b/CHANGELOG.adoc @@ -0,0 +1,35 @@ += Changelog + +== Unreleased + +* If specified, request’s body encoding is now applied, else defaults to UTF-8 (https://github.com/clj-commons/clj-http-lite/issues/18[#18]) (https://github.com/lread[@lread]) +* User info from request URL now applied to basic auth (https://github.com/clj-commons/clj-http-lite/issues/34[#34]) (https://github.com/lread[@lread]) +* Nested query and form parameters are now automatically flattened (https://github.com/clj-commons/clj-http-lite/issues/43[#43]) (https://github.com/lread[@lread]) +* The `:insecure?` option is now applied only to the current request (https://github.com/clj-commons/clj-http-lite/issues/45[#45]) (https://github.com/lread[@lread]) +* Docs +** Docstrings and README reviewed and updated (https://github.com/lread[@lread]) +** Guidance on mocking HTTP requests now makes sense (https://github.com/clj-commons/clj-http-lite/issues/51[#51]) (thanks https://github.com/anderseknert[@anderseknert]!) +** Move from Markdown to AsciiDoc (https://github.com/lread[@lread]) +* Quality +** Automated CI testing added for Windows (https://github.com/clj-commons/clj-http-lite/issues/21[#21]) (https://github.com/lread[@lread]) +** Babashka now exercised under full test suite (https://github.com/clj-commons/clj-http-lite/issues/48[#48]) (https://github.com/lread[@lread]) + +== 0.4.384 + +* Support self-signed certificates via `:insecure? true` option +* Remove dependency on slingshot +* Move to `org.clj-commons` group +* Add compatibility with https://babashka.org/[babashka] +* *Feature:* Support for`:oauth-token` (https://github.com/martinklepsch/clj-http-lite/pull/7[#1]) + +== 0.4.3 + +* *Feature:* Parse link headers from response and put them under `:links` (https://github.com/martinklepsch/clj-http-lite/pull/1[#1]) + +== 0.4.2 + +* Add type hints for GraalVM (https://github.com/clj-commons/clj-http-lite/pull/2[#2]) + +== 0.4.0 + +* *Feature:* Java 9/10 Compatibility diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4513a095..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -### Unreleased - -- If specified, request's body encoding is now applied, else defaults to UTF-8 ([#18](https://github.com/clj-commons/clj-http-lite/issues/18)) ([@lread](https://github.com/lread)) -- User info from request URL now applied to basic auth ([#34](https://github.com/clj-commons/clj-http-lite/issues/34)) ([@lread](https://github.com/lread)) -- Nested query and form parameters are now automatically flattened ([#43](https://github.com/clj-commons/clj-http-lite/issues/43)) ([@lread](https://github.com/lread)) -- The `:insecure?` option is now applied only to the current request ([#45](https://github.com/clj-commons/clj-http-lite/issues/45)) ([@lread](https://github.com/lread)) -- Docs - - Docstrings and README reviewed and updated ([@lread](https://github.com/lread)) - - Guidance on mocking HTTP requests now makes sense ([#51](https://github.com/clj-commons/clj-http-lite/issues/51)) (thanks [@anderseknert](https://github.com/anderseknert)!) -- Quality - - Automated CI testing added for Windows ([#21](https://github.com/clj-commons/clj-http-lite/issues/21)) ([@lread](https://github.com/lread)) - - Babashka now exercised under full test suite ([#48](https://github.com/clj-commons/clj-http-lite/issues/48)) ([@lread](https://github.com/lread)) - -### 0.4.384 - -- Support self-signed certificates via `:insecure? true` option -- Remove dependency on slingshot -- Move to `org.clj-commons` group -- Add compatibility with [babashka](https://babashka.org/) -- **Feature:** Support for`:oauth-token` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/7)) - -### 0.4.3 - -- **Feature:** Parse link headers from response and put them under `:links` ([#1](https://github.com/martinklepsch/clj-http-lite/pull/1)) - -### 0.4.2 - -- Add type hints for GraalVM ([#2](https://github.com/clj-commons/clj-http-lite/pull/2)) - -### 0.4.0 - -- **Feature:** Java 9/10 Compatibility diff --git a/README.md b/README.adoc similarity index 62% rename from README.md rename to README.adoc index b084c027..1a640785 100644 --- a/README.md +++ b/README.adoc @@ -1,52 +1,71 @@ -# `clj-http-lite` -[![cljdoc badge](https://cljdoc.org/badge/org.clj-commons/clj-http-lite)](https://cljdoc.org/d/org.clj-commons/clj-http-lite) [![CI tests](https://github.com/clj-commons/clj-http-lite/workflows/Tests/badge.svg)](https://github.com/clj-commons/clj-http-lite/actions) [![Clojars](https://img.shields.io/clojars/v/org.clj-commons/clj-http-lite.svg)](https://clojars.org/org.clj-commons/clj-http-lite) [![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://babashka.org) [![Join chat](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://clojurians.slack.com/archives/C03UZ1Y8414) - -A Clojure HTTP library similar to [clj-http](http://github.com/dakrone/clj-http), but more lightweight. Compatible with Babashka and GraalVM. - -> This is a clj-commons maintained fork of the archived [`hiredman/clj-http-lite`](https://github.com/hiredman/clj-http-lite) repo. - -[Installation](#installation) | [Usage](#usage) | [Design](#design) | [Development](#development) - -## Installation - -`clj-http-lite` is available as a Maven artifact from [Clojars](https://clojars.org/org.clj-commons/clj-http-lite): - -```clojure -[org.clj-commons/clj-http-lite "0.4.392"] -``` - -## Differences from clj-http - -- Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection -- No automatic JSON decoding for response bodies -- No automatic request body encoding beyond charset and url encoding of form params -- No cookie support -- No multipart form uploads -- No persistent connection support -- Fewer options -- namespace rename clj-http.* -> clj-http.lite.* - -Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you'd like to see in clj-http-lite. We can discuss. -## History - -- Sep 2011 - [dakrone/clj-http](https://github.com/dakrone/clj-http) created (and is still actively maintained) -- Feb 2012 - [hiredman/clj-http-lite](https://github.com/hiredman/clj-http-lite) (now archived) forked from `dakrone/clj-http` to use Java's HttpURLConnection instead of Apache HttpClient. -- Jul 2018 - `martinklepsch/clj-http-lite` forked from `hiredman/clj-http-lite` for new development and maintenance -- Nov 2021 - Martin transfered his fork to `clj-commons/clj-http-lite` so it could get the ongoing love it needs from the Clojure community - -## Usage - -The main HTTP client functionality is provided by the -`clj-http.lite.client` namespace: - -```clojure += `clj-http-lite` +:toclevels: 4 +:toc: macro +:lib-version: 0.4.392 +:project-src-coords: clj-commons/clj-http-lite +:project-mvn-coords: org.clj-commons/clj-http-lite +:url-doc: https://cljdoc.org/d/{project-mvn-coords} + +// Badges +link:{url-doc}[image:https://cljdoc.org/badge/{project-mvn-coords}[Cljdoc]] +https://github.com/{project-src-coords}/actions/workflows/ci.yml[image:https://github.com/{project-src-coords}/workflows/Tests/badge.svg[GitHub Actions tests]] +https://clojars.org/{project-mvn-coords}[image:https://img.shields.io/clojars/v/{project-mvn-coords}.svg[Clojars]] +https://babashka.org[image:https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg[bb compatible]] +https://clojurians.slack.com/archives/C03UZ1Y8414[image:https://img.shields.io/badge/slack-join_chat-brightgreen.svg[Join chat]] + +A Clojure HTTP library similar to http://github.com/dakrone/clj-http[clj-http], but more lightweight. +Compatible with Babashka and GraalVM. +____ +This is a clj-commons maintained fork of the archived https://github.com/hiredman/clj-http-lite[`hiredman/clj-http-lite`] repo. +____ + +toc::[] + +== Installation + +`clj-http-lite` is available as a Maven artifact from https://clojars.org/org.clj-commons/clj-http-lite[Clojars]: + +[source,clojure,subs="attributes+"] +---- +[org.clj-commons/clj-http-lite "{lib-version}"] +---- + +== Differences from clj-http + +* Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection +* No automatic JSON decoding for response bodies +* No automatic request body encoding beyond charset and url encoding of form params +* No cookie support +* No multipart form uploads +* No persistent connection support +* Fewer options +* namespace rename clj-http.* -> clj-http.lite.* + +Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you’d like to see in clj-http-lite. +We can discuss. + +== History + +* Sep 2011 - https://github.com/dakrone/clj-http[dakrone/clj-http] created (and is still actively maintained) +* Feb 2012 - https://github.com/hiredman/clj-http-lite[hiredman/clj-http-lite] (now archived) forked from `dakrone/clj-http` to use Java’s HttpURLConnection instead of Apache HttpClient. +* Jul 2018 - `martinklepsch/clj-http-lite` forked from `hiredman/clj-http-lite` for new development and maintenance +* Nov 2021 - Martin transfered his fork to `clj-commons/clj-http-lite` so it could get the ongoing love it needs from the Clojure community + +== Usage + +=== General +The main HTTP client functionality is provided by the `clj-http.lite.client` namespace: + +[source,clojure] +---- (require '[clj-http.lite.client :as client]) -``` +---- -The client supports simple `get`, `head`, `put`, `post`, and `delete` -requests. They all return Ring-style response maps: +The client supports simple `get`, `head`, `put`, `post`, and `delete` requests. +They all return Ring-style response maps: -```clojure +[source,clojure] +---- (client/get "https://google.com") => {:status 200 :headers {"date" "Wed, 17 Aug 2022 21:37:58 GMT" @@ -54,11 +73,12 @@ requests. They all return Ring-style response maps: "content-type" "text/html; charset=ISO-8859-1" ...} :body "..."} -``` +---- -**TIP**: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many examples. +TIP: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many examples. -```clojure +[source,clojure] +---- (client/get "https://httpbin.org/user-agent") ;; Tell the server you'd like a json response @@ -97,21 +117,23 @@ requests. They all return Ring-style response maps: ;; Query parameters can be specified as a map (client/get "https://httpbin.org/get" {:query-params {"q" "foo, bar"}}) -``` +---- The client transparently accepts and decompresses the `gzip` and `deflate` content encodings. -```Clojure +[source,clojure] +---- (client/get "https://httpbin.org/gzip") (client/get "https://httpbin.org/deflate") -``` +---- -### Nested params +=== Nested params Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatically flattened to `a[b]=1`. -```clojure +[source,clojure] +---- (-> (client/get "https://httpbin.org/get" {:query-params {:one {:two 2 :three 3}}}) :body @@ -139,11 +161,12 @@ Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatic }, ... } -``` +---- -### Request body coercion +=== Request body coercion -```clojure +[source,clojure] +---- ;; body as byte-array (client/post "https://httbin.org/post" {:body (.getBytes "testing123")}) @@ -165,11 +188,12 @@ Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatic (with-open [is (io/input-stream "clj-http-lite-test.txt")] (client/post "https://httpbin.org/post" {:body (io/input-stream "clj-http-lite-test.txt")}) ) -``` +---- -### Output body coercion +=== Output body coercion -```clojure +[source,clojure] +---- ;; The default response body is a string body (client/get "https://clojure.org") @@ -189,23 +213,23 @@ Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatic (let [res (client/get "https://clojure.org" {:as :stream})] (with-open [body-stream (:body res)] (slurp body-stream))) -``` +---- -A more general `request` function is also available, which is useful -as a primitive for building higher-level interfaces: +A more general `request` function is also available, which is useful as a primitive for building higher-level interfaces: -```clojure +[source,clojure] +---- (defn api-action [method path & [opts]] (client/request (merge {:method method :url (str "https://some.api/" path)} opts))) -``` +---- -### Exceptions +=== Exceptions -The client will throw exceptions on, exceptional HTTP status -codes. Clj-http-lite throws an `ex-info` with the response as `ex-data`. +The client will throw exceptions on, exceptional HTTP status codes. Clj-http-lite throws an `ex-info` with the response as `ex-data`. -```clojure +[source,clojure] +---- (client/get "https://httpbin.org/404") ;; => ExceptionInfo clj-http: status 404 clojure.core/ex-info (core.clj:4617) @@ -214,32 +238,33 @@ codes. Clj-http-lite throws an `ex-info` with the response as `ex-data`. (-> *e ex-data keys) ;; => (:headers :status :body) -``` +---- You can suppress HTTP status exceptions and handle them yourself: -``` clojure +[source,clojure] +---- (client/get "https://httpbin.org/404" {:throw-exceptions false}) -``` +---- -Or ignore an unknown host (methods return 'nil' if this is set to true and the host does not exist: +Or ignore an unknown host (methods return `nil' if this is set to true and the host does not exist: -``` clojure +[source,clojure] +---- (client/get "http://aoeuntahuf89o.com" {:ignore-unknown-host? true}) ;; => nil -``` +---- -### Proxies +=== Proxies -A proxy can be specified by setting the Java properties: -`.proxyHost` and `.proxyPort` where `` is the client -scheme used (normally 'http' or 'https'). +A proxy can be specified by setting the Java properties: `.proxyHost` and `.proxyPort` where `` is the client scheme used (normally `http' or `https'). -## Mocking clj-http responses +== Mocking clj-http-lite responses Mocking responses from the clj-http-lite client in tests is easily accomplished with e.g. `with-redefs`: -```clojure +[source,clojure] +---- (defn my-http-function [] (let [response (client/get "https://example.org")] (when (= 200 (:status response)) @@ -248,11 +273,12 @@ Mocking responses from the clj-http-lite client in tests is easily accomplished (deftest my-http-function-test (with-redefs [client/get (fn [_] {:status 200 :headers {"content-type" "text/plain"} :body "OK"})] (is (= (my-http-function) "OK")))) -``` +---- More advanced mocking may be performed by matching attributes in the `request`, like the `mock-response` function below. -```clojure +[source,clojure] +---- (ns http-test (:require [clojure.data.json :as json] [clojure.test :refer [deftest is testing]] @@ -291,79 +317,85 @@ More advanced mocking may be performed by matching attributes in the `request`, (is (= (get-users) ["joe" "jane" "bob"]))) (testing "access admin page" (is (= (get-admin) "403 Forbidden"))))) -``` +---- -## GraalVM Native Image Tips +== GraalVM Native Image Tips -You'll need to enable url protocols when building your native image. +You’ll need to enable url protocols when building your native image. -See [GraalVM docs](https://www.graalvm.org/22.2/reference-manual/native-image/dynamic-features/URLProtocols/). +See https://www.graalvm.org/22.2/reference-manual/native-image/dynamic-features/URLProtocols/[GraalVM docs]. -## Design +== Design -The design of `clj-http` (and therefore `clj-http-lite`) is inspired by the -[Ring](https://github.com/ring-clojure/ring) protocol for Clojure HTTP -server applications. +The design of `clj-http` (and therefore `clj-http-lite`) is inspired by the https://github.com/ring-clojure/ring[Ring] protocol for Clojure HTTP server applications. -The client in `clj-http.lite.core` makes HTTP requests according to a given -Ring request map and returns Ring response maps corresponding to the -resulting HTTP response. The function `clj-http.lite.client/request` uses -Ring-style middleware to layer functionality over the core HTTP -request/response implementation. Methods like `clj-http.lite.client/get` -are sugar over this `clj-http.lite.client/request` function. +The client in `clj-http.lite.core` makes HTTP requests according to a given Ring request map and returns Ring response maps corresponding to the resulting HTTP response. +The function `clj-http.lite.client/request` uses Ring-style middleware to layer functionality over the core HTTP request/response implementation. +Methods like `clj-http.lite.client/get` are sugar over this `clj-http.lite.client/request` function. -## Development +== Development -### Clojure JVM Tests +=== Clojure JVM Tests Optionally: -```shell + +[source,shell] +---- $ bb clean $ bb deps -``` +---- Run all Clojure tests against minimum supported version of Clojure (1.8): -```shell +[source,shell] +---- $ bb test:jvm -``` +---- Run tests against a specific Clojure version, for example 1.11 -```shell + +[source,shell] +---- $ bb test:jvm --clj-version 1.11 -``` +---- You can also include cognitect test runner options: -```shell + +[source,shell] +---- $ bb test:jvm --clj-version 1.9 --namespace-regex '*.sanity.*' -``` +---- -### Babashka Tests +=== Babashka Tests To run the entire test suite under Babashka: -```shell +[source,shell] +---- $ bb test:bb -``` +---- + You can also include cognitect test runner options: -```shell + +[source,shell] +---- $ bb test:bb --var clj-http.lite.integration-test/roundtrip -``` +---- -### Linting +=== Linting Our CI workflow lints sources with clj-kondo, and you can too! -```shell +[source,shell] +---- $ bb lint -``` +---- -### Release +=== Release -To release a new version, run `bb publish` which will push a new tag. CI will -take care of the rest. +To release a new version, run `bb publish` which will push a new tag. +CI will take care of the rest. -## License +== License -Released under the MIT License: - +Released under the MIT License: http://www.opensource.org/licenses/mit-license.php From 946b8daa134de3f1c2ca50aff715932bea3bf5fa Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 26 Aug 2022 13:00:28 -0400 Subject: [PATCH 119/143] docs: README edits [skip ci] (#62) --- README.adoc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/README.adoc b/README.adoc index 1a640785..6998e03a 100644 --- a/README.adoc +++ b/README.adoc @@ -23,11 +23,18 @@ toc::[] == Installation -`clj-http-lite` is available as a Maven artifact from https://clojars.org/org.clj-commons/clj-http-lite[Clojars]: +Clojure cli users, add the following under `:deps` in your `deps.edn` file. + +Babashka users, add the following under `:deps` in your `bb.edn` file: +[source,clojure,subs="attributes+"] +---- + org.clj-commons/clj-http-lite {:mnv/version "{lib-version}"} +---- + +Lein users, add the following into the `:dependencies` vector in your `project.clj` file: [source,clojure,subs="attributes+"] ---- -[org.clj-commons/clj-http-lite "{lib-version}"] + [org.clj-commons/clj-http-lite "{lib-version}"] ---- == Differences from clj-http @@ -39,7 +46,7 @@ toc::[] * No multipart form uploads * No persistent connection support * Fewer options -* namespace rename clj-http.* -> clj-http.lite.* +* namespace rename `clj-http.*` -> `clj-http.lite.*` Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you’d like to see in clj-http-lite. We can discuss. @@ -54,7 +61,7 @@ We can discuss. == Usage === General -The main HTTP client functionality is provided by the `clj-http.lite.client` namespace: +HTTP client functionality is provided by the `clj-http.lite.client` namespace: [source,clojure] ---- @@ -75,7 +82,7 @@ They all return Ring-style response maps: :body "..."} ---- -TIP: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many examples. +TIP: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many of our examples. [source,clojure] ---- @@ -226,7 +233,8 @@ A more general `request` function is also available, which is useful as a primit === Exceptions -The client will throw exceptions on, exceptional HTTP status codes. Clj-http-lite throws an `ex-info` with the response as `ex-data`. +When a server returns an exceptional HTTP status code, by default, clj-http-lite throws an `ex-info` exception. +The response is included as `ex-data`. [source,clojure] ---- @@ -240,14 +248,15 @@ The client will throw exceptions on, exceptional HTTP status codes. Clj-http-lit ;; => (:headers :status :body) ---- -You can suppress HTTP status exceptions and handle them yourself: +You can suppress HTTP status exceptions and handle them yourself via the `:throw-exceptions` option: [source,clojure] ---- (client/get "https://httpbin.org/404" {:throw-exceptions false}) ---- -Or ignore an unknown host (methods return `nil' if this is set to true and the host does not exist: +You can choose to ignore an unknown host via `:ingore-unknown-host?` option. +When enabled, requests return `nil` if the host is not found. [source,clojure] ---- @@ -393,7 +402,7 @@ $ bb lint === Release -To release a new version, run `bb publish` which will push a new tag. +To release a new version, run `bb publish` which will push a new tag. CI will take care of the rest. == License From 51380e4e94c8156f26ab6e03f1d849516e61a6da Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 26 Aug 2022 17:43:23 -0400 Subject: [PATCH 120/143] docs: split out README to guides [skip ci] (#64) Also add: - Credit for contributors. - Interesting alternatives - Info on supported and dev environments - Contributing guidance --- README.adoc | 410 +++-------------------------------- bb/tasks.clj | 1 + doc/01-user-guide.adoc | 350 ++++++++++++++++++++++++++++++ doc/02-developer-guide.adoc | 106 +++++++++ doc/03-maintainer-guide.adoc | 19 ++ doc/cljdoc.edn | 5 +- 6 files changed, 515 insertions(+), 376 deletions(-) create mode 100644 doc/01-user-guide.adoc create mode 100644 doc/02-developer-guide.adoc create mode 100644 doc/03-maintainer-guide.adoc diff --git a/README.adoc b/README.adoc index 6998e03a..c42d35a7 100644 --- a/README.adoc +++ b/README.adoc @@ -1,7 +1,4 @@ = `clj-http-lite` -:toclevels: 4 -:toc: macro -:lib-version: 0.4.392 :project-src-coords: clj-commons/clj-http-lite :project-mvn-coords: org.clj-commons/clj-http-lite :url-doc: https://cljdoc.org/d/{project-mvn-coords} @@ -19,392 +16,55 @@ ____ This is a clj-commons maintained fork of the archived https://github.com/hiredman/clj-http-lite[`hiredman/clj-http-lite`] repo. ____ -toc::[] +== Documentation -== Installation +* link:doc/01-user-guide.adoc[User Guide] +* link:doc/02-developer-guide.adoc[Developer Guide] -Clojure cli users, add the following under `:deps` in your `deps.edn` file. + -Babashka users, add the following under `:deps` in your `bb.edn` file: -[source,clojure,subs="attributes+"] ----- - org.clj-commons/clj-http-lite {:mnv/version "{lib-version}"} ----- +== Used In... +Some project using clj-http-lite are: -Lein users, add the following into the `:dependencies` vector in your `project.clj` file: +* https://github.com/clj-holmes/clj-holmes[clj-holmes] - Static application security tool for finding vulnerable Clojure code +* https://cljdoc.org/[cljdoc site] (https://github.com/cljdoc/cljdoc[sources]) - A central documentation hub for the Clojure community +* https://github.com/clj-commons/etaoin[Etaoin] - Pure Clojure WebDriver protocol implementation +* https://github.com/djblue/portal[portal] (for tests) - A clojure tool to navigate through your data +* https://github.com/sethtrain/raven-clj[raven-clj] - A Clojure interface to Sentry +* https://github.com/epiccastle/spire[spire] - pragmatic provisioning using Clojure -[source,clojure,subs="attributes+"] ----- - [org.clj-commons/clj-http-lite "{lib-version}"] ----- +Don't see your project listed? Let us know, we'll be happy to include it! -== Differences from clj-http +== People -* Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection -* No automatic JSON decoding for response bodies -* No automatic request body encoding beyond charset and url encoding of form params -* No cookie support -* No multipart form uploads -* No persistent connection support -* Fewer options -* namespace rename `clj-http.*` -> `clj-http.lite.*` +=== Contributors -Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you’d like to see in clj-http-lite. -We can discuss. +A big thank you to al the people who have contributed directly to clj-http-lite! -== History +* https://github.com/katox[@katox] +* https://github.com/sattvik[@sattvik] +* https://github.com/AdamClements[@AdamClements] +* https://github.com/ivarref[@ivarref] +* https://github.com/imrekoszo[@imrekoszo] +* https://github.com/avichalp[@avichalp] +* https://github.com/arnaudbos[@arnaudbos] +* https://github.com/gaberger[@gaberger] +* https://github.com/vemv[@vemv] +* https://github.com/deas[@deas] +* https://github.com/anderseknert[@anderseknert] -* Sep 2011 - https://github.com/dakrone/clj-http[dakrone/clj-http] created (and is still actively maintained) -* Feb 2012 - https://github.com/hiredman/clj-http-lite[hiredman/clj-http-lite] (now archived) forked from `dakrone/clj-http` to use Java’s HttpURLConnection instead of Apache HttpClient. -* Jul 2018 - `martinklepsch/clj-http-lite` forked from `hiredman/clj-http-lite` for new development and maintenance -* Nov 2021 - Martin transfered his fork to `clj-commons/clj-http-lite` so it could get the ongoing love it needs from the Clojure community +Don't see your name? Our apologies! Let us know and we'll add you in. -== Usage +=== Founders -=== General -HTTP client functionality is provided by the `clj-http.lite.client` namespace: +* https://github.com/dakrone[@dakrone] - the creator of clj-http +* https://github.com/hiredman[@hiredman] - the creator of clj-http-lite +* https://github.com/martinklepsch[@martinklepsch] - maintainer of clj-http-lite -[source,clojure] ----- -(require '[clj-http.lite.client :as client]) ----- +=== Current Active Maintainers -The client supports simple `get`, `head`, `put`, `post`, and `delete` requests. -They all return Ring-style response maps: - -[source,clojure] ----- -(client/get "https://google.com") -=> {:status 200 - :headers {"date" "Wed, 17 Aug 2022 21:37:58 GMT" - "cache-control" "private, max-age=0" - "content-type" "text/html; charset=ISO-8859-1" - ...} - :body "..."} ----- - -TIP: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many of our examples. - -[source,clojure] ----- -(client/get "https://httpbin.org/user-agent") - -;; Tell the server you'd like a json response -(client/get "https://httpbin.org/user-agent" {:accept :json}) - -;; Or maybe you'd like html back -(client/get "https://httpbin.org/html" {:accept "text/html"}) - -;; Various options -(client/post "https://httpbin.org/anything" - {:basic-auth ["joe" "cool"] - :body "{\"json\": \"input\"}" - :headers {"X-Api-Version" "2"} - :content-type :json - :socket-timeout 1000 - :conn-timeout 1000 - :accept :json}) - -;; Need to contact a server with an untrusted SSL cert? -(client/get "https://expired.badssl.com" {:insecure? true}) - -;; By default we automatically follow 30* redirects... -(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org") - -;; ... but you don't have to -(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org" - {:follow-redirects false}) - -;; Send form params as a urlencoded body -(client/post "https://httpbin.org/post" {:form-params {:foo "bar"}}) - -;; Basic authentication -(client/get "https://joe:cool@httpbin.org/basic-auth/joe/cool") -(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth ["joe" "cool"]}) -(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth "joe:cool"}) - -;; Query parameters can be specified as a map -(client/get "https://httpbin.org/get" {:query-params {"q" "foo, bar"}}) ----- - -The client transparently accepts and decompresses the `gzip` and `deflate` content encodings. - -[source,clojure] ----- -(client/get "https://httpbin.org/gzip") - -(client/get "https://httpbin.org/deflate") ----- - -=== Nested params - -Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatically flattened to `a[b]=1`. - -[source,clojure] ----- -(-> (client/get "https://httpbin.org/get" - {:query-params {:one {:two 2 :three 3}}}) - :body - println) -{ - "args": { - "one[three]": "3", - "one[two]": "2" - }, - ... -} - -(-> (client/post "https://httpbin.org/post" - {:form-params {:one {:two 2 - :three {:four {:five 5}}} - :six 6}}) - :body - println) -{ - ... - "form": { - "one[three][four][five]": "5", - "one[two]": "2", - "six": "6" - }, - ... -} ----- - -=== Request body coercion - -[source,clojure] ----- -;; body as byte-array -(client/post "https://httbin.org/post" {:body (.getBytes "testing123")}) - -;; body from a string -(client/post "https://httpbin.org/post" {:body "testing456"}) - -;; string :body-encoding is optional and defaults to "UTF-8" -(client/post "https://httpbin.org/post" - {:body "mystring" :body-encoding "UTF-8"}) - -;; body from a file -(require '[clojure.java.io :as io]) -(spit "clj-http-lite-test.txt" "from a file") -(client/post "https://httpbin.org/post" - {:body (io/file "clj-http-lite-test.txt") - :body-encoding "UTF-8"}) - -;; from a stream -(with-open [is (io/input-stream "clj-http-lite-test.txt")] - (client/post "https://httpbin.org/post" - {:body (io/input-stream "clj-http-lite-test.txt")}) ) ----- - -=== Output body coercion - -[source,clojure] ----- -;; The default response body is a string body -(client/get "https://clojure.org") - -;; Coerce to a byte-array -(client/get "http://clojure.org" {:as :byte-array}) - -;; Coerce to a string with using a specific charset, default is UTF-8 -(client/get "http://clojure.org" {:as "US-ASCII"}) - -;; Try to automatically coerce the body based on the content-type -;; response header charset -(client/get "https://google.com" {:as :auto}) - -;; Return the body as a stream -;; Note that the connection to the server will NOT be closed until the -;; stream has been read -(let [res (client/get "https://clojure.org" {:as :stream})] - (with-open [body-stream (:body res)] - (slurp body-stream))) ----- - -A more general `request` function is also available, which is useful as a primitive for building higher-level interfaces: - -[source,clojure] ----- -(defn api-action [method path & [opts]] - (client/request - (merge {:method method :url (str "https://some.api/" path)} opts))) ----- - -=== Exceptions - -When a server returns an exceptional HTTP status code, by default, clj-http-lite throws an `ex-info` exception. -The response is included as `ex-data`. - -[source,clojure] ----- -(client/get "https://httpbin.org/404") -;; => ExceptionInfo clj-http: status 404 clojure.core/ex-info (core.clj:4617) - -(-> *e ex-data :status) -;; => 404 - -(-> *e ex-data keys) -;; => (:headers :status :body) ----- - -You can suppress HTTP status exceptions and handle them yourself via the `:throw-exceptions` option: - -[source,clojure] ----- -(client/get "https://httpbin.org/404" {:throw-exceptions false}) ----- - -You can choose to ignore an unknown host via `:ingore-unknown-host?` option. -When enabled, requests return `nil` if the host is not found. - -[source,clojure] ----- -(client/get "http://aoeuntahuf89o.com" {:ignore-unknown-host? true}) -;; => nil ----- - -=== Proxies - -A proxy can be specified by setting the Java properties: `.proxyHost` and `.proxyPort` where `` is the client scheme used (normally `http' or `https'). - -== Mocking clj-http-lite responses - -Mocking responses from the clj-http-lite client in tests is easily accomplished with e.g. `with-redefs`: - -[source,clojure] ----- -(defn my-http-function [] - (let [response (client/get "https://example.org")] - (when (= 200 (:status response)) - (:body response)))) - -(deftest my-http-function-test - (with-redefs [client/get (fn [_] {:status 200 :headers {"content-type" "text/plain"} :body "OK"})] - (is (= (my-http-function) "OK")))) ----- - -More advanced mocking may be performed by matching attributes in the `request`, like the `mock-response` function below. - -[source,clojure] ----- -(ns http-test - (:require [clojure.data.json :as json] - [clojure.test :refer [deftest is testing]] - [clj-http.lite.client :as client])) - -(defn send-report [data] - (:body (client/post "https://example.com/reports" {:body data}))) - -(defn get-users [] - (json/read-str (:body (client/get "https://example.com/users")))) - -(defn get-admin [] - (let [response (client/get "https://example.com/admin")] - (if (= 200 (:status response)) - (:body response) - "403 Forbidden"))) - -(defn mock-response [{:keys [url method body] :as request}] - (condp = [url method] - ["https://example.com/reports" :post] - {:status 201 :headers {"content-type" "text/plain"} :body (str "created: " body)} - - ["https://example.com/users" :get] - {:status 200 :headers {"content-type" "application/json"} :body (json/write-str ["joe" "jane" "bob"])} - - ["https://example.com/admin" :get] - {:status 403 :headers {"content-type" "text/plain"} :body "forbidden"} - - (throw (ex-info "unexpected request" request)))) - -(deftest send-report-test - (with-redefs [client/request mock-response] - (testing "sending report" - (is (= (send-report {:balance 100}) "created: {:balance 100}"))) - (testing "list users" - (is (= (get-users) ["joe" "jane" "bob"]))) - (testing "access admin page" - (is (= (get-admin) "403 Forbidden"))))) ----- - -== GraalVM Native Image Tips - -You’ll need to enable url protocols when building your native image. - -See https://www.graalvm.org/22.2/reference-manual/native-image/dynamic-features/URLProtocols/[GraalVM docs]. - -== Design - -The design of `clj-http` (and therefore `clj-http-lite`) is inspired by the https://github.com/ring-clojure/ring[Ring] protocol for Clojure HTTP server applications. - -The client in `clj-http.lite.core` makes HTTP requests according to a given Ring request map and returns Ring response maps corresponding to the resulting HTTP response. -The function `clj-http.lite.client/request` uses Ring-style middleware to layer functionality over the core HTTP request/response implementation. -Methods like `clj-http.lite.client/get` are sugar over this `clj-http.lite.client/request` function. - -== Development - -=== Clojure JVM Tests - -Optionally: - -[source,shell] ----- -$ bb clean -$ bb deps ----- - -Run all Clojure tests against minimum supported version of Clojure (1.8): - -[source,shell] ----- -$ bb test:jvm ----- - -Run tests against a specific Clojure version, for example 1.11 - -[source,shell] ----- -$ bb test:jvm --clj-version 1.11 ----- - -You can also include cognitect test runner options: - -[source,shell] ----- -$ bb test:jvm --clj-version 1.9 --namespace-regex '*.sanity.*' ----- - -=== Babashka Tests - -To run the entire test suite under Babashka: - -[source,shell] ----- -$ bb test:bb ----- - -You can also include cognitect test runner options: - -[source,shell] ----- -$ bb test:bb --var clj-http.lite.integration-test/roundtrip ----- - -=== Linting - -Our CI workflow lints sources with clj-kondo, and you can too! - -[source,shell] ----- -$ bb lint ----- - -=== Release - -To release a new version, run `bb publish` which will push a new tag. -CI will take care of the rest. +* https://github.com/lread[@lread] +* https://github.com/borkdude[@borkdude] == License +We respect the original license at time of forking from clj-http: Released under the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/bb/tasks.clj b/bb/tasks.clj index 70a931ef..16973457 100644 --- a/bb/tasks.clj +++ b/bb/tasks.clj @@ -28,6 +28,7 @@ (let [;; commit count + 1 for README update cc (inc (shared/git-count-revs)) tag (str "Release-" (shared/version cc))] + ;; TODO: Update (replace-version "README.md" shared/base-version cc) (replace-version "project.clj" shared/base-version cc) (shell "git add README.md project.clj") diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc new file mode 100644 index 00000000..c11d280a --- /dev/null +++ b/doc/01-user-guide.adoc @@ -0,0 +1,350 @@ += User Guide +:toclevels: 5 +:toc: +:lib-version: 0.4.392 + +== Introduction +Clj-http-lite is a Clojure, Babashka and GraalVM compatible liteweight subset of http://github.com/dakrone/clj-http[clj-http]. + +=== Differences from clj-http + +* Instead of Apache HttpClient, clj-http-lite uses HttpURLConnection +* No automatic JSON decoding for response bodies +* No automatic request body encoding beyond charset and url encoding of form params +* No cookie support +* No multipart form uploads +* No persistent connection support +* Fewer options +* namespace rename `clj-http.*` -> `clj-http.lite.*` + +Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you’d like to see in clj-http-lite. +We can discuss. + +=== Supported Environments [[supported-envs]] + +* JDK 8, 11, 17 +* Clojure 1.8 runtime and above +* Babashka current release +* Windows, Linux, macOS + +=== History + +* Sep 2011 - https://github.com/dakrone/clj-http[dakrone/clj-http] created (and is still actively maintained) +* Feb 2012 - https://github.com/hiredman/clj-http-lite[hiredman/clj-http-lite] (now archived) forked from `dakrone/clj-http` to use Java’s HttpURLConnection instead of Apache HttpClient. +* Jul 2018 - `martinklepsch/clj-http-lite` forked from `hiredman/clj-http-lite` for new development and maintenance +* Nov 2021 - Martin transfered his fork to `clj-commons/clj-http-lite` so it could get the ongoing love it needs from the Clojure community + +=== Interesting Alternatives + +Maybe clj-http-lite is not your cup of tea? Some alternatives to explore: + +Clojure based: + +* http://github.com/dakrone/clj-http[clj-http] - heavier than clj-http-lite, but has many more features + +Babashka compatible: + +* https://github.com/schmee/java-http-clj[java-http-clj] - Clojure wrapper for java.net.http with async, HTTP/2 and WebSockets +* https://github.com/http-kit/http-kit[http-kit] - minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support +* https://github.com/gnarroway/hato[hato] - An HTTP client for Clojure, wrapping JDK 11's HttpClient +* https://github.com/babashka/babashka.curl[babashka.curl] - A tiny curl wrapper via idiomatic Clojure, inspired by clj-http, Ring and friends + +== Installation + +Clojure cli users, add the following under `:deps` in your `deps.edn` file. + +Babashka users, add the following under `:deps` in your `bb.edn` file: +[source,clojure,subs="attributes+"] +---- + org.clj-commons/clj-http-lite {:mnv/version "{lib-version}"} +---- + +Lein users, add the following into the `:dependencies` vector in your `project.clj` file: + +[source,clojure,subs="attributes+"] +---- + [org.clj-commons/clj-http-lite "{lib-version}"] +---- + +== Usage + +=== General +HTTP client functionality is provided by the `clj-http.lite.client` namespace: + +[source,clojure] +---- +(require '[clj-http.lite.client :as client]) +---- + +The client supports simple `get`, `head`, `put`, `post`, and `delete` requests. +They all return Ring-style response maps: + +[source,clojure] +---- +(client/get "https://google.com") +=> {:status 200 + :headers {"date" "Wed, 17 Aug 2022 21:37:58 GMT" + "cache-control" "private, max-age=0" + "content-type" "text/html; charset=ISO-8859-1" + ...} + :body "..."} +---- + +TIP: We encourage you to try out these examples in your REPL, `httpbin.org` is a free HTTP test playground and used in many of our examples. + +[source,clojure] +---- +(client/get "https://httpbin.org/user-agent") + +;; Tell the server you'd like a json response +(client/get "https://httpbin.org/user-agent" {:accept :json}) + +;; Or maybe you'd like html back +(client/get "https://httpbin.org/html" {:accept "text/html"}) + +;; Various options +(client/post "https://httpbin.org/anything" + {:basic-auth ["joe" "cool"] + :body "{\"json\": \"input\"}" + :headers {"X-Api-Version" "2"} + :content-type :json + :socket-timeout 1000 + :conn-timeout 1000 + :accept :json}) + +;; Need to contact a server with an untrusted SSL cert? +(client/get "https://expired.badssl.com" {:insecure? true}) + +;; By default we automatically follow 30* redirects... +(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org") + +;; ... but you don't have to +(client/get "https://httpbin.org/redirect-to?url=https%3A%2F%2Fclojure.org" + {:follow-redirects false}) + +;; Send form params as a urlencoded body +(client/post "https://httpbin.org/post" {:form-params {:foo "bar"}}) + +;; Basic authentication +(client/get "https://joe:cool@httpbin.org/basic-auth/joe/cool") +(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth ["joe" "cool"]}) +(client/get "https://httpbin.org/basic-auth/joe/cool" {:basic-auth "joe:cool"}) + +;; Query parameters can be specified as a map +(client/get "https://httpbin.org/get" {:query-params {"q" "foo, bar"}}) +---- + +The client transparently accepts and decompresses the `gzip` and `deflate` content encodings. + +[source,clojure] +---- +(client/get "https://httpbin.org/gzip") + +(client/get "https://httpbin.org/deflate") +---- + +=== Nested params + +Nested parameter `{:a {:b 1}}` in `:form-params` or `:query-params` is automatically flattened to `a[b]=1`. + +[source,clojure] +---- +(-> (client/get "https://httpbin.org/get" + {:query-params {:one {:two 2 :three 3}}}) + :body + println) +{ + "args": { + "one[three]": "3", + "one[two]": "2" + }, + ... +} + +(-> (client/post "https://httpbin.org/post" + {:form-params {:one {:two 2 + :three {:four {:five 5}}} + :six 6}}) + :body + println) +{ + ... + "form": { + "one[three][four][five]": "5", + "one[two]": "2", + "six": "6" + }, + ... +} +---- + +=== Request body coercion + +[source,clojure] +---- +;; body as byte-array +(client/post "https://httbin.org/post" {:body (.getBytes "testing123")}) + +;; body from a string +(client/post "https://httpbin.org/post" {:body "testing456"}) + +;; string :body-encoding is optional and defaults to "UTF-8" +(client/post "https://httpbin.org/post" + {:body "mystring" :body-encoding "UTF-8"}) + +;; body from a file +(require '[clojure.java.io :as io]) +(spit "clj-http-lite-test.txt" "from a file") +(client/post "https://httpbin.org/post" + {:body (io/file "clj-http-lite-test.txt") + :body-encoding "UTF-8"}) + +;; from a stream +(with-open [is (io/input-stream "clj-http-lite-test.txt")] + (client/post "https://httpbin.org/post" + {:body (io/input-stream "clj-http-lite-test.txt")}) ) +---- + +=== Output body coercion + +[source,clojure] +---- +;; The default response body is a string body +(client/get "https://clojure.org") + +;; Coerce to a byte-array +(client/get "http://clojure.org" {:as :byte-array}) + +;; Coerce to a string with using a specific charset, default is UTF-8 +(client/get "http://clojure.org" {:as "US-ASCII"}) + +;; Try to automatically coerce the body based on the content-type +;; response header charset +(client/get "https://google.com" {:as :auto}) + +;; Return the body as a stream +;; Note that the connection to the server will NOT be closed until the +;; stream has been read +(let [res (client/get "https://clojure.org" {:as :stream})] + (with-open [body-stream (:body res)] + (slurp body-stream))) +---- + +A more general `request` function is also available, which is useful as a primitive for building higher-level interfaces: + +[source,clojure] +---- +(defn api-action [method path & [opts]] + (client/request + (merge {:method method :url (str "https://some.api/" path)} opts))) +---- + +=== Exceptions + +When a server returns an exceptional HTTP status code, by default, clj-http-lite throws an `ex-info` exception. +The response is included as `ex-data`. + +[source,clojure] +---- +(client/get "https://httpbin.org/404") +;; => ExceptionInfo clj-http: status 404 clojure.core/ex-info (core.clj:4617) + +(-> *e ex-data :status) +;; => 404 + +(-> *e ex-data keys) +;; => (:headers :status :body) +---- + +You can suppress HTTP status exceptions and handle them yourself via the `:throw-exceptions` option: + +[source,clojure] +---- +(client/get "https://httpbin.org/404" {:throw-exceptions false}) +---- + +You can choose to ignore an unknown host via `:ingore-unknown-host?` option. +When enabled, requests return `nil` if the host is not found. + +[source,clojure] +---- +(client/get "http://aoeuntahuf89o.com" {:ignore-unknown-host? true}) +;; => nil +---- + +=== Proxies + +A proxy can be specified by setting the Java properties: `.proxyHost` and `.proxyPort` where `` is the client scheme used (normally `http' or `https'). + +== Mocking clj-http-lite responses + +Mocking responses from the clj-http-lite client in tests is easily accomplished with e.g. `with-redefs`: + +[source,clojure] +---- +(defn my-http-function [] + (let [response (client/get "https://example.org")] + (when (= 200 (:status response)) + (:body response)))) + +(deftest my-http-function-test + (with-redefs [client/get (fn [_] {:status 200 :headers {"content-type" "text/plain"} :body "OK"})] + (is (= (my-http-function) "OK")))) +---- + +More advanced mocking may be performed by matching attributes in the `request`, like the `mock-response` function below. + +[source,clojure] +---- +(ns http-test + (:require [clojure.data.json :as json] + [clojure.test :refer [deftest is testing]] + [clj-http.lite.client :as client])) + +(defn send-report [data] + (:body (client/post "https://example.com/reports" {:body data}))) + +(defn get-users [] + (json/read-str (:body (client/get "https://example.com/users")))) + +(defn get-admin [] + (let [response (client/get "https://example.com/admin")] + (if (= 200 (:status response)) + (:body response) + "403 Forbidden"))) + +(defn mock-response [{:keys [url method body] :as request}] + (condp = [url method] + ["https://example.com/reports" :post] + {:status 201 :headers {"content-type" "text/plain"} :body (str "created: " body)} + + ["https://example.com/users" :get] + {:status 200 :headers {"content-type" "application/json"} :body (json/write-str ["joe" "jane" "bob"])} + + ["https://example.com/admin" :get] + {:status 403 :headers {"content-type" "text/plain"} :body "forbidden"} + + (throw (ex-info "unexpected request" request)))) + +(deftest send-report-test + (with-redefs [client/request mock-response] + (testing "sending report" + (is (= (send-report {:balance 100}) "created: {:balance 100}"))) + (testing "list users" + (is (= (get-users) ["joe" "jane" "bob"]))) + (testing "access admin page" + (is (= (get-admin) "403 Forbidden"))))) +---- + +== GraalVM Native Image Tips + +You’ll need to enable url protocols when building your native image. + +See https://www.graalvm.org/22.2/reference-manual/native-image/dynamic-features/URLProtocols/[GraalVM docs]. + +== Design + +The design of `clj-http` (and therefore `clj-http-lite`) is inspired by the https://github.com/ring-clojure/ring[Ring] protocol for Clojure HTTP server applications. + +The client in `clj-http.lite.core` makes HTTP requests according to a given Ring request map and returns Ring response maps corresponding to the resulting HTTP response. +The function `clj-http.lite.client/request` uses Ring-style middleware to layer functionality over the core HTTP request/response implementation. +Methods like `clj-http.lite.client/get` are sugar over this `clj-http.lite.client/request` function. diff --git a/doc/02-developer-guide.adoc b/doc/02-developer-guide.adoc new file mode 100644 index 00000000..6cd56b78 --- /dev/null +++ b/doc/02-developer-guide.adoc @@ -0,0 +1,106 @@ += Developer Guide + +== Contributing + +We very much appreciate contributions from the community. + +=== Issue First Please + +If you have an idea or a fix, please do raise a GitHub issue before investing in any coding effort. That way we can discuss first. +Writing code is the easy part, maintaining it forever is the hard part. + +That said, if you notice a simple typo, a PR without an issue is fine. + +=== Submitting a Pull Request + +Please never force push on your PR, as this makes reviewing incremental changes impossible for us. +When we merge your PR, we'll usually squash it, so that will clean up any rambling work in progress. + +== Environmental Overview + +=== Developer Prerequisites + +The current version of Babashka. + +* Our scripts use Babashka to launch Clojure, so you don't absolutely need the Clojure cli's `clojure` command. +* JDK, see <<01-user-guide.adoc#supported-envs,supported environments>> + +=== Babashka Compatibility + +Clj-http-lite is babashka compatible. + +Babashka supports everything that clj-http-lite needs, but when making changes, be aware that your code must also work under Babashka. + +If your change requires something Babashka does not currently support, we can bring it up with the babashka team, things like adding a class are usually approved. + +== Docs + +All documentation is written in AsciiDoc. +@lread likes to follow https://asciidoctor.org/docs/asciidoc-recommended-practices/#one-sentence-per-line[AsciiDoc best practice of one sentence per line] but won't be entirely pedantic about that. + +We host our docs on cljdoc. + +== Babashka Tasks + +We use Babashka tasks, to see all available tasks run: + +[source,shell] +---- +bb tasks +---- + +=== Clojure JVM Tests + +Optionally: + +[source,shell] +---- +$ bb clean +$ bb deps +---- + +Run all Clojure tests against minimum supported version of Clojure (1.8): + +[source,shell] +---- +$ bb test:jvm +---- + +Run tests against a specific Clojure version, for example 1.11 + +[source,shell] +---- +$ bb test:jvm --clj-version 1.11 +---- + +You can also include cognitect test runner options: + +[source,shell] +---- +$ bb test:jvm --clj-version 1.9 --namespace-regex '*.sanity.*' +---- + +=== Babashka Tests[bb-tests] + +To run the entire test suite under Babashka: + +[source,shell] +---- +$ bb test:bb +---- + +You can also include cognitect test runner options: + +[source,shell] +---- +$ bb test:bb --var clj-http.lite.integration-test/roundtrip +---- + +=== Linting + +Our CI workflow lints sources with clj-kondo, and you can too! + +[source,shell] +---- +$ bb lint +---- diff --git a/doc/03-maintainer-guide.adoc b/doc/03-maintainer-guide.adoc new file mode 100644 index 00000000..23bd4d65 --- /dev/null +++ b/doc/03-maintainer-guide.adoc @@ -0,0 +1,19 @@ += Maintainer Guide + +== Introduction + +Notes for project maintainers. + +== Releasing + +The following is *NOT* currently automated: + +* reviewing and updating changelog "unreleased" section +* generating a GitHub release + +To release a new version, run `bb publish` which will push a new tag. +CI will: + +* run lint and tests +* create a thin jar +* publish the jar to clojars diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn index e942b3f9..19cf2bec 100644 --- a/doc/cljdoc.edn +++ b/doc/cljdoc.edn @@ -1,3 +1,6 @@ {:cljdoc.doc/tree [["Readme" {:file "README.md"}] - ["Changelog" {:file "CHANGELOG.md"}]]} + ["Changelog" {:file "CHANGELOG.md"}] + ["User Guide" {:file "doc/01-user-guide.adoc"}] + ["Developer Guide" {:file "doc/02-developer-guide.adoc"}] + ["Maintainer Guide" {:file "doc/03-maintainer-guide.adoc"}]]} From da57aa99b8882ef6dde32ddc88e8bce9c4d96103 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 29 Aug 2022 18:09:44 -0400 Subject: [PATCH 121/143] docs: tell cljdoc toc about md->adoc (#66) --- doc/cljdoc.edn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn index 19cf2bec..ec774c2c 100644 --- a/doc/cljdoc.edn +++ b/doc/cljdoc.edn @@ -1,6 +1,6 @@ {:cljdoc.doc/tree - [["Readme" {:file "README.md"}] - ["Changelog" {:file "CHANGELOG.md"}] + [["Readme" {:file "README.adoc"}] + ["Changelog" {:file "CHANGELOG.adoc"}] ["User Guide" {:file "doc/01-user-guide.adoc"}] ["Developer Guide" {:file "doc/02-developer-guide.adoc"}] ["Maintainer Guide" {:file "doc/03-maintainer-guide.adoc"}]]} From 862b112cc8358fd01660124bede6e29bdea4719d Mon Sep 17 00:00:00 2001 From: Lee Read Date: Sun, 4 Sep 2022 18:13:22 -0400 Subject: [PATCH 122/143] tests: revert change for missing bb exceptions (#67) Babashka now includes formerly missing exceptions --- test/clj_http/lite/integration_test.clj | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/test/clj_http/lite/integration_test.clj b/test/clj_http/lite/integration_test.clj index 5ae81150..cb184790 100644 --- a/test/clj_http/lite/integration_test.clj +++ b/test/clj_http/lite/integration_test.clj @@ -93,10 +93,9 @@ (try (request {:request-method :get :uri "/timeout" :socket-timeout 1}) (is false "expected a throw") - (catch Exception ^Exception e - (is (or (= "Read timed out" (.getMessage e)) - (let [^Exception cause (.getCause e)] - (= "Read timed out" (.getMessage cause)))))))) + (catch Exception e + (is (or (= java.net.SocketTimeoutException (class e)) + (= java.net.SocketTimeoutException (class (.getCause e)))))))) (deftest delete-with-body (let [resp (request {:request-method :delete :uri "/delete-with-body" @@ -110,19 +109,13 @@ :scheme :https :server-name "localhost" :server-port (:https-port *server*)}] - (try - (request client-opts) - (is false "expected a throw") - (catch Exception ^Exception e - (is (re-find #"SunCertPathBuilderException" (.getMessage e))))) + (is (thrown? javax.net.ssl.SSLException + (request client-opts))) (let [resp (request (assoc client-opts :insecure? true))] (is (= 200 (:status resp))) (is (= "get" (slurp-body resp)))) - (try - (request client-opts) - (is false "expected a throw") - (catch Exception ^Exception e - (is (re-find #"SunCertPathBuilderException" (.getMessage e))))))) + (is (thrown? javax.net.ssl.SSLException + (request client-opts))))) (deftest t-save-request-obj (let [resp (request {:request-method :post :uri "/post" From a89282944e500b5a0fc5ef15af9f713cfead558e Mon Sep 17 00:00:00 2001 From: mokshasoft Date: Fri, 16 Sep 2022 14:28:21 +0200 Subject: [PATCH 123/143] Update 01-user-guide.adoc (#68) Fixed typo in installation instructions. --- doc/01-user-guide.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index c11d280a..4ca0af86 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -55,7 +55,7 @@ Clojure cli users, add the following under `:deps` in your `deps.edn` file. + Babashka users, add the following under `:deps` in your `bb.edn` file: [source,clojure,subs="attributes+"] ---- - org.clj-commons/clj-http-lite {:mnv/version "{lib-version}"} + org.clj-commons/clj-http-lite {:mvn/version "{lib-version}"} ---- Lein users, add the following into the `:dependencies` vector in your `project.clj` file: From d3255e00219300ce8f2864e60d6dc83fbc392d36 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 16 Sep 2022 10:07:08 -0400 Subject: [PATCH 124/143] docs: readme: people: thanks @mokshasoft [skip ci] --- README.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/README.adoc b/README.adoc index c42d35a7..b6c529a7 100644 --- a/README.adoc +++ b/README.adoc @@ -50,6 +50,7 @@ A big thank you to al the people who have contributed directly to clj-http-lite! * https://github.com/vemv[@vemv] * https://github.com/deas[@deas] * https://github.com/anderseknert[@anderseknert] +* https://github.com/mokshasoft[@mokshasoft] Don't see your name? Our apologies! Let us know and we'll add you in. From e9210b73f1e535364ece1534ebd7832610c36c4b Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 19 Sep 2022 15:55:32 -0400 Subject: [PATCH 125/143] disable PR review invite for codeowners [skip ci] --- .github/CODEOWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1dc6f1cf..8d9658b8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,3 @@ -@borkdude @lread @martinklepsch @slipset +# Code owners are auto-invited to review PRs including files matching specified pattern(s). +# We opt out of this by only matching the CODEOWNERS file itself. +.github/CODEOWNERS @borkdude @lread @martinklepsch @slipset From 5cdeb5f4a029ec21c758b4392931bc292e173cfd Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 29 Sep 2022 17:21:19 -0400 Subject: [PATCH 126/143] Automate publishing of release (#69) Invoked via `bb publish` Read doc/03-maintainer-guide.adoc for details Details of interest: - using neil convention of storing version in deps.edn - tagging with v1.2.3 instead of Release-1.2.3 - now at version 1.x (was 0.x) - version patch is now release count, was commit count, next version should be 1.0.13 - hiredman - 4 releases - martinklepsch - 4 releases - clj-commons - 4 releases - addition of anemic pom includes artifact description which gets displayed by services like clojars and cljdoc Closes #65 --- .github/workflows/ci.yml | 190 ------------------- .github/workflows/publish.yml | 37 ++++ .github/workflows/shared-setup/action.yml | 49 +++++ .github/workflows/tests.yml | 70 +++++++ .gitignore | 2 - CHANGELOG.adoc | 19 +- bb.edn | 86 ++++++--- bb/tasks.clj | 38 ---- build.clj | 66 +++---- build/build_shared.clj | 23 +++ build_shared.clj | 15 -- deps.edn | 9 +- doc/01-user-guide.adoc | 1 + doc/03-maintainer-guide.adoc | 70 +++++-- pom.xml | 34 ++++ script/ci_publish.clj | 67 +++++++ script/download_deps.clj | 23 +++ {bb => script}/lint.clj | 2 +- script/publish.clj | 216 ++++++++++++++++++++++ {bb => script}/test_jvm.clj | 0 version.edn | 1 - 21 files changed, 681 insertions(+), 337 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/shared-setup/action.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 bb/tasks.clj create mode 100644 build/build_shared.clj delete mode 100644 build_shared.clj create mode 100644 pom.xml create mode 100644 script/ci_publish.clj create mode 100644 script/download_deps.clj rename {bb => script}/lint.clj (96%) create mode 100644 script/publish.clj rename {bb => script}/test_jvm.clj (100%) delete mode 100644 version.edn diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 6d6430e7..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,190 +0,0 @@ -name: Tests -on: [push, pull_request] - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3.0.2 - - - name: Clojure deps cache - uses: actions/cache@v3 - with: - path: | - ~/.m2/repository - ~/.deps.clj - ~/.gitlibs - key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} - restore-keys: cljdeps- - - - name: Setup Java - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '17' - - - name: Setup Clojure Tooling - uses: DeLaGuardo/setup-clojure@9.4 - with: - bb: 'latest' - - - name: Tools versions - run: | - echo "bb --version" - bb --version - echo "java -version" - java -version - - - name: Bring down deps - run: bb deps - - - name: Lint - run: bb lint - - test-jvm: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - os: ["ubuntu", "windows"] - clojure-version: ["1.8", "1.9", "1.10", "1.11"] - java-version: ["8", "11", "17"] - - name: ${{ matrix.os }} clj-${{ matrix.clojure-version }} jdk${{ matrix.java-version }} - - steps: - - name: Checkout - uses: actions/checkout@v3.0.2 - - - name: Clojure deps cache - uses: actions/cache@v3 - with: - path: | - ~/.m2/repository - ~/.deps.clj - ~/.gitlibs - key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} - restore-keys: cljdeps- - - - name: Setup Java - uses: actions/setup-java@v3 - with: - distribution: "temurin" - java-version: ${{ matrix.java-version }} - - - name: Setup Clojure Tooling - uses: DeLaGuardo/setup-clojure@9.4 - with: - bb: 'latest' - - - name: Tools versions - run: | - echo "bb --version" - bb --version - echo "java -version" - java -version - - - name: Bring down deps - run: bb deps - - - name: Run tests - run: bb test:jvm --clj-version ${{ matrix.clojure-version }} - - test-bb: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - os: ["ubuntu", "windows"] - - name: ${{ matrix.os }} bb - - steps: - - name: Checkout - uses: actions/checkout@v3.0.2 - - - name: Clojure deps cache - uses: actions/cache@v3 - with: - path: | - ~/.m2/repository - ~/.deps.clj - ~/.gitlibs - key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} - restore-keys: cljdeps- - - - name: Setup Java - uses: actions/setup-java@v3 - with: - distribution: "temurin" - java-version: '17' - - - name: Setup Clojure Tooling - uses: DeLaGuardo/setup-clojure@9.4 - with: - bb: 'latest' - - - name: Tools versions - run: | - echo "bb --version" - bb --version - echo "java -version" - java -version - - - name: Run tests - run: bb test:bb - - deploy: - runs-on: ubuntu-latest - needs: - - lint - - test-jvm - - test-bb - - steps: - - name: Checkout - uses: actions/checkout@v3.0.2 - with: - fetch-depth: 0 - - - name: Clojure deps cache - uses: actions/cache@v3 - with: - path: | - ~/.m2/repository - ~/.deps.clj - ~/.gitlibs - key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} - restore-keys: cljdeps- - - - name: Setup Java - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '17' - - - name: Setup Clojure Tooling - uses: DeLaGuardo/setup-clojure@9.4 - with: - bb: 'latest' - cli: 'latest' - - - name: Tools versions - run: | - echo "bb --version" - bb --version - echo "clojure --version" - clojure --version - echo "java -version" - java -version - - - name: Bring down deps - run: bb deps - - - name: Deploy - env: - CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }} - CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }} - run: clojure -T:build maybe-deploy diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..8bd0e3ab --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,37 @@ +name: publish +on: + push: + tags: + - 'v\d+.*' + +jobs: + test: + uses: ./.github/workflows/tests.yml + + publish: + environment: publish + runs-on: ubuntu-latest + needs: [test] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup + uses: ./.github/workflows/shared-setup + with: + jdk: '8' + + - name: Deploy to clojars + env: + CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }} + CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }} + run: bb -ci-clojars-deploy + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bb -ci-github-create-release + + - name: Inform Cljdoc + run: bb -ci-cljdoc-request-build diff --git a/.github/workflows/shared-setup/action.yml b/.github/workflows/shared-setup/action.yml new file mode 100644 index 00000000..f994f8c8 --- /dev/null +++ b/.github/workflows/shared-setup/action.yml @@ -0,0 +1,49 @@ +name: 'shared setup' +inputs: + jdk: + description: 'jdk version' + required: true + shell: + # shell must be specified for run:s for composite actions + description: 'which shell to use' + required: false + default: bash + +runs: + using: 'composite' + + steps: + - name: Clojure deps cache + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository + ~/.deps.clj + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }} + restore-keys: cljdeps- + + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: ${{ inputs.jdk }} + + - name: Install Clojure Tools + uses: DeLaGuardo/setup-clojure@9.5 + with: + cli: 'latest' + bb: 'latest' + + - name: Tools Versions + shell: ${{ inputs.shell }} + run: | + echo "java -version" + java -version + echo "bb --version" + bb --version + echo "clojure --version" + clojure --version + - name: Download Clojure Dependencies + shell: ${{ inputs.shell }} + run: bb download-deps diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..98add901 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,70 @@ +name: tests +on: + # allow this workflow to be called from other workflows, namely: publish + workflow_call: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3.0.2 + + - name: Setup + uses: ./.github/workflows/shared-setup + with: + jdk: '11' + + - name: Lint + run: bb lint + + test-jvm: + runs-on: ${{ matrix.os.name }}-latest + strategy: + fail-fast: false + matrix: + os: [{name: 'windows', shell: 'pwsh'}, {name: 'ubuntu', shell: 'bash'}] + clojure-version: ["1.8", "1.9", "1.10", "1.11"] + jdk: ['8', '11', '17'] + + name: ${{ matrix.os.name }} clj-${{ matrix.clojure-version }} jdk${{ matrix.java-version }} + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup + uses: ./.github/workflows/shared-setup + with: + jdk: ${{ matrix.jdk }} + shell: ${{ matrix.os.shell }} + + - name: Run tests + run: bb test:jvm --clj-version ${{ matrix.clojure-version }} + + test-bb: + runs-on: ${{ matrix.os.name }}-latest + strategy: + fail-fast: false + matrix: + os: [{name: 'windows', shell: 'pwsh'}, {name: 'ubuntu', shell: 'bash'}] + + name: ${{ matrix.os.name }} bb + + steps: + - name: Checkout + uses: actions/checkout@v3.0.2 + + - name: Setup + uses: ./.github/workflows/shared-setup + with: + jdk: '11' + shell: ${{ matrix.os.shell }} + + - name: Run tests + run: bb test:bb diff --git a/.gitignore b/.gitignore index a643f88c..4ec1b8b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -build target lib *.dot @@ -7,7 +6,6 @@ lib syntax: glob creds.clj Manifest.txt -pom.xml aws.clj *.ser *.class diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 16a2ca16..5580886e 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,16 @@ = Changelog +A release with known breaking changes is marked with: + +* [breaking] you probably need to change your code +* [minor breaking] you likely don't need to change your code + +// DO NOT EDIT: the "Unreleased" section header is automatically updated by bb publish +// bb publish will fail on any of: +// - unreleased section not found, +// - unreleased section empty +// - optional attribute is not [breaking] or [minor breaking] +// (adjust these in publish.clj as you see fit) == Unreleased * If specified, request’s body encoding is now applied, else defaults to UTF-8 (https://github.com/clj-commons/clj-http-lite/issues/18[#18]) (https://github.com/lread[@lread]) @@ -14,7 +25,7 @@ ** Automated CI testing added for Windows (https://github.com/clj-commons/clj-http-lite/issues/21[#21]) (https://github.com/lread[@lread]) ** Babashka now exercised under full test suite (https://github.com/clj-commons/clj-http-lite/issues/48[#48]) (https://github.com/lread[@lread]) -== 0.4.384 +== v0.4.392 - 2021-11-18 * Support self-signed certificates via `:insecure? true` option * Remove dependency on slingshot @@ -22,14 +33,14 @@ * Add compatibility with https://babashka.org/[babashka] * *Feature:* Support for`:oauth-token` (https://github.com/martinklepsch/clj-http-lite/pull/7[#1]) -== 0.4.3 +== v0.4.3 - 2019-12-04 * *Feature:* Parse link headers from response and put them under `:links` (https://github.com/martinklepsch/clj-http-lite/pull/1[#1]) -== 0.4.2 +== v0.4.1 - 2018-10-17 * Add type hints for GraalVM (https://github.com/clj-commons/clj-http-lite/pull/2[#2]) -== 0.4.0 +== v0.4.0 - 2018-10-17 * *Feature:* Java 9/10 Compatibility diff --git a/bb.edn b/bb.edn index 4bc67afa..b4b7c962 100644 --- a/bb.edn +++ b/bb.edn @@ -1,29 +1,59 @@ -{:paths ["." "bb"] +{:paths ["script" "build"] :deps {lread/status-line {:git/url "https://github.com/lread/status-line.git" - :sha "35ed39645038e81b42cb15ed6753b8462e60a06d"}} - :tasks - {:requires ([tasks :as t]) - deps - {:doc "Bring down all the clojure deps" - :task (t/deps)} - clean - {:doc "Delete any work dirs" - :task (clojure "-T:build clean")} - test:jvm - {:doc "Runs tests under JVM Clojure [--clj-version] (recognizes cognitect test-runner args)" - :task test-jvm/-main} - test:bb - {:doc "Runs tests under babashka Clojure (recognizes cognitect test-runner args)" - :extra-paths ["src" "test" "test-resources"] - :extra-deps {io.github.cognitect-labs/test-runner - {:git/tag "v0.5.1" :git/sha "dfb30dd"} - org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace" - :git/sha "16b8c53174a5c9d89d6e0ce4128aa30b071aabdf"}} - :requires ([cognitect.test-runner :as tr]) - :task (apply tr/-main *command-line-args*)} - lint - {:doc "[--rebuild] Lint source code" - :task lint/-main} - publish - {:doc "Trigger a release to clojars" - :task (t/publish)}}} + :sha "35ed39645038e81b42cb15ed6753b8462e60a06d"} + version-clj/version-clj {:mvn/version "2.0.2"}} + :tasks {;; setup + :requires ([babashka.fs :as fs] + [clojure.string :as string] + [lread.status-line :as status]) + :enter (let [{:keys [name]} (current-task)] (status/line :head "TASK %s %s" name (string/join " " *command-line-args*))) + :leave (let [{:keys [name]} (current-task)] (status/line :detail "\nTASK %s done." name)) + + ;; tasks + clean + {:doc "Delete any work/cache dirs" + :task (doseq [dir ["target" ".cpcache"]] + (if (fs/exists? dir) + (do + (status/line :detail "Deleting: %s" dir) + (fs/delete-tree dir)) + (status/line :detail "Does not exist: %s" dir)))} + download-deps + {:doc "Bring down all the clojure deps" + :task download-deps/-main} + test:jvm + {:doc "Runs tests under JVM Clojure [--clj-version] (recognizes cognitect test-runner args)" + :task test-jvm/-main} + test:bb + {:doc "Runs tests under babashka Clojure (recognizes cognitect test-runner args)" + :extra-paths ["src" "test" "test-resources"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.1" :git/sha "dfb30dd"} + org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace" + :git/sha "16b8c53174a5c9d89d6e0ce4128aa30b071aabdf"}} + :requires ([cognitect.test-runner :as tr]) + :task (apply tr/-main *command-line-args*)} + lint + {:doc "[--rebuild] Lint source code" + :task lint/-main} + pubcheck + {:doc "run only publish checks (without publishing)" + :task publish/pubcheck} + publish + {:doc "Trigger a release to clojars" + :task publish/-main} + neil ;; let's not rely on a random version of neil + {:doc "Pinned version of babashka/neil (used in scripting)" + :extra-deps {babashka/neil {:git/url "https://github.com/babashka/neil.git" + :sha "6fc58cc6a4253c2c15f05135f1610ab3d46d961f"}} + :task babashka.neil/-main} + ;; hidden tasks, no need for folks to be trying these ci invoked tasks + -ci-clojars-deploy + {:doc "triggered on ci by release tag" + :task ci-publish/clojars-deploy} + -ci-github-create-release + {:doc "triggered on ci by release tag" + :task ci-publish/github-create-release} + -ci-cljdoc-request-build + {:doc "ask cljdoc to build docs for new release" + :task ci-publish/cljdoc-request-build}}} diff --git a/bb/tasks.clj b/bb/tasks.clj deleted file mode 100644 index 16973457..00000000 --- a/bb/tasks.clj +++ /dev/null @@ -1,38 +0,0 @@ -(ns tasks - (:require [babashka.tasks :refer [shell clojure]] - [build-shared :as shared] - [clojure.edn :as edn] - [clojure.string :as str])) - -(defn deps [] - (let [aliases (->> "deps.edn" - slurp - edn/read-string - :aliases - keys)] - ;; one at a time because aliases with :replace-deps or override-deps will... well... you know. - (println "Bring down default deps") - (clojure "-P") - (doseq [a aliases] - (println "Bring down deps for alias" a) - (clojure "-P" (str "-M" a))))) - -(defn replace-version [file version cc] - (spit file - (str/replace (slurp file) - (re-pattern (format "(%s)\\.(\\d+)" version)) - (fn [[_ version _]] - (str version "." cc))))) - -(defn publish [] - (let [;; commit count + 1 for README update - cc (inc (shared/git-count-revs)) - tag (str "Release-" (shared/version cc))] - ;; TODO: Update - (replace-version "README.md" shared/base-version cc) - (replace-version "project.clj" shared/base-version cc) - (shell "git add README.md project.clj") - (shell "git commit -m 'Bump version in README'") - (shell "git push") - (shell "git tag" tag) - (shell "git push origin" tag))) diff --git a/build.clj b/build.clj index e6f22bf1..18cadf83 100644 --- a/build.clj +++ b/build.clj @@ -1,67 +1,43 @@ (ns build - (:require [build-shared :as shared] - [clojure.string :as str] + (:require [build-shared] [clojure.tools.build.api :as b])) -(def lib 'org.clj-commons/clj-http-lite) -(def version (shared/version (shared/git-count-revs))) +(def version (build-shared/lib-version)) +(def lib (build-shared/lib-artifact-name)) + +;; build constants (def class-dir "target/classes") (def basis (b/create-basis {:project "deps.edn"})) (def jar-file (format "target/%s-%s.jar" (name lib) version)) -(def github-repo "https://github.com/clj-commons/clj-http-lite") - -(defn clean [_] - (b/delete {:path "target"})) -(defn jar [opts] - (let [opts (merge {:class-dir class-dir +(defn jar [_] + (println "jarring version" version) + (b/write-pom {:class-dir class-dir :lib lib :version version + :scm {:tag (build-shared/version->tag version)} :basis basis - :src-dirs ["src"]} - opts) - opts (assoc opts :scm - (cond-> {:url "https://github.com/clj-commons/clj-http-lite"} - (:tag opts) (assoc :tag (:tag opts))))] - (b/write-pom opts)) - (b/copy-dir {:src-dirs ["src" "resources"] + :src-dirs ["src"]}) + (b/copy-dir {:src-dirs ["src"] :target-dir class-dir}) (b/jar {:class-dir class-dir :jar-file jar-file})) +(defn install [_] + (jar {}) + (println "installing version" version) + (b/install {:basis basis + :lib lib + :version version ;; can't remember why we need to repeat version here, it is in jar-file + :jar-file jar-file + :class-dir class-dir})) + (defn deploy [opts] (jar opts) + (println "deploy") ((requiring-resolve 'deps-deploy.deps-deploy/deploy) (merge {:installer :remote :artifact jar-file :pom-file (b/pom-path {:lib lib :class-dir class-dir})} opts)) opts) - -(def release-marker "Release-") - -(defn extract-version [tag] - (str/replace-first tag release-marker "")) - -(defn ci-tag [] - (when (= "tag" (System/getenv "GITHUB_REF_TYPE")) - (System/getenv "GITHUB_REF_NAME"))) - -(defn maybe-deploy [opts] - (if-let [tag (ci-tag)] - (do - (println "Found tag " tag) - (if (re-find (re-pattern release-marker) tag) - (do - (println "Releasing to clojars...") - (-> opts - (assoc :lib lib - :version (extract-version tag) - :tag tag) - (deploy))) - (do - (println "Tag is not a release tag, skipping deploy") - opts))) - (do - (println "No tag found, skipping deploy") - opts))) diff --git a/build/build_shared.clj b/build/build_shared.clj new file mode 100644 index 00000000..95ff0859 --- /dev/null +++ b/build/build_shared.clj @@ -0,0 +1,23 @@ +(ns build-shared + "a few things that are both needed by bb script code and build.clj" + (:require [clojure.string :as string] + [clojure.edn :as edn])) + +(defn- project-info [] + (-> (edn/read-string (slurp "deps.edn")) + :aliases :neil :project)) + +(def version-tag-prefix "v") + +(defn lib-version [] + (-> (project-info) :version)) + +(defn lib-artifact-name [] + (-> (project-info) :name)) + +(defn version->tag [version] + (str version-tag-prefix version)) + +(defn tag->version [ci-tag] + (and (string/starts-with? ci-tag version-tag-prefix) + (string/replace-first ci-tag version-tag-prefix ""))) diff --git a/build_shared.clj b/build_shared.clj deleted file mode 100644 index c433599e..00000000 --- a/build_shared.clj +++ /dev/null @@ -1,15 +0,0 @@ -(ns build-shared - (:require [clojure.edn :as edn] - [clojure.java.shell :refer [sh]] - [clojure.string :as str])) - -(defn git-count-revs [] - (-> (apply sh (str/split "git rev-list HEAD --count" #" ")) - :out - str/trim - Integer/parseInt)) - -(def base-version (edn/read-string (slurp "version.edn"))) - -(defn version [revs] - (str base-version "." revs)) diff --git a/deps.edn b/deps.edn index 9683d21f..211c233e 100644 --- a/deps.edn +++ b/deps.edn @@ -1,12 +1,17 @@ {:paths ["src"] :deps {org.clojure/clojure {:mvn/version "1.8.0"}} :aliases - {:1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} + {;; we use babashka/neil for project attributes + ;; publish workflow references these values (and automatically bumps patch) + :neil {:project {:version "1.0.12" + :name org.clj-commons/clj-http-lite}} + :1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.1"}}} :build - {:deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} + {:extra-paths ["build"] + :deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} slipset/deps-deploy {:mvn/version "0.2.0"}} :ns-default build} :http-server ;; used for to support integration tests diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index 4ca0af86..214a6a70 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -1,6 +1,7 @@ = User Guide :toclevels: 5 :toc: +// DO NOT EDIT: the lib-version parameter is automatically updated by bb publish :lib-version: 0.4.392 == Introduction diff --git a/doc/03-maintainer-guide.adoc b/doc/03-maintainer-guide.adoc index 23bd4d65..2dee9675 100644 --- a/doc/03-maintainer-guide.adoc +++ b/doc/03-maintainer-guide.adoc @@ -1,19 +1,67 @@ = Maintainer Guide +:toc: levels 4 -== Introduction +== Audience +You are a maintainer of this project. -Notes for project maintainers. +== Publishing a New Release +Is invoked from the command line via: -== Releasing +[source,shell] +---- +bb publish +---- -The following is *NOT* currently automated: +It validates: -* reviewing and updating changelog "unreleased" section -* generating a GitHub release +* local git +** you are on master branch +** do not have any uncommitted code +** do not have any unpushed commits +* changelog +** Has an "Unreleased" section with content -To release a new version, run `bb publish` which will push a new tag. -CI will: +Then locally: -* run lint and tests -* create a thin jar -* publish the jar to clojars +. bumps the version `` (our scheme is `major.minor.`) +** Our version is stored in `deps.edn` under `:aliases` `:neil` `:project` `:version` +. applies version to: +.. `doc/01-user-guide.adoc` +.. `CHANGELOG.adoc` +. git commits: `deps.edn` `doc/01-user-guide.adoc` `CHANGELOG.adoc` +. git tags with release tag `v` +. pushes commit +. pushes tag + +Then up on CI, the CI publish workflow is only triggered when it sees a release tag: + +. CI tests workflow is invoked +. a release jar is published to clojars +. a GitHub release is created +. cljdoc is informed of the new release + +TIP: you can run just the publish validations alone via `bb pubcheck` + +== Relevant Sources + +Scripts: + +. `bb.edn` - tasks entry point +. `script/publish.clj` - client side work +. `script/ci_publish.clj` - ci side work + +CI - We use GitHub Actions for this project + +. `.github/workflows/tests.yml` +. `.github/workflows/publish.yml` + +== CI Config + +Clojars secrets are protected under the `publish` environment which is only referenced by `publish.yml`. + +== Expected Oddities + +When publishing, you will see both the `tests` workflow triggered and the `publish` workflow triggered (which also invokes the `tests` workflow). + +This extra running of the `tests` workflow is GitHub Actions responding to changes committed as part of the publishing work. +A bit annoying, but harmless. diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..f73559f9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + clj-commons/clj-http-lite + A lite version of clj-http that uses the jre's HttpURLConnection + https://github.com/clj-commons/clj-http-lite + + + MIT + http://www.opensource.org/licenses/mit-license.php + + + + https://github.com/clj-commons/clj-http-lite + scm:git:git://github.com/clj-commons/clj-http-lite.git + scm:git:ssh://git@github.com/clj-commons/clj-http-lite.git + + + UTF-8 + + + + clojars + https://repo.clojars.org/ + + + + + clojars + Clojars repository + https://clojars.org/repo + + + diff --git a/script/ci_publish.clj b/script/ci_publish.clj new file mode 100644 index 00000000..c84de103 --- /dev/null +++ b/script/ci_publish.clj @@ -0,0 +1,67 @@ +(ns ci-publish + "Publish work we invoke from GitHub Actions. + Separated out here: + - to make it clear what is happening on ci + - rate of change here should be less/different than in publish namespace" + (:require [babashka.tasks :as t] + [lread.status-line :as status] + [build-shared])) + +(def changelog-url "https://github.com/clj-commons/clj-http-lite/blob/master/CHANGELOG.adoc") + +(defn- assert-on-ci [] + (when (not (System/getenv "CI")) + (status/die 1 "to be run from continuous integration server only"))) + +(defn- ci-tag [] + (when (= "tag" (System/getenv "GITHUB_REF_TYPE")) + (System/getenv "GITHUB_REF_NAME"))) + +(defn- analyze-ci-tag [] + (let [tag (ci-tag)] + (if (not tag) + (status/die 1 "CI tag not found") + (let [version-from-tag (build-shared/tag->version tag) + lib-version (build-shared/lib-version)] + (cond + (not version-from-tag) + (status/die 1 "Not recognized as version tag: %s" tag) + + (not= version-from-tag lib-version) + (status/die 1 "Lib version %s does not match version from tag %s" + lib-version version-from-tag) + :else + {:tag tag + :version lib-version}))))) + +;; +;; Task entry points +;; + +(defn clojars-deploy [] + (assert-on-ci) + (analyze-ci-tag) ;; fail on unexpected version tag + (t/clojure "-T:build deploy")) + +(defn github-create-release [] + (assert-on-ci) + (let [{:keys [tag]} (analyze-ci-tag)] + (t/shell "gh release create" + tag + "--title" tag + "--notes" (format "[Changelog](%s#%s)" changelog-url tag)))) + +(defn cljdoc-request-build [] + (assert-on-ci) + (let [{:keys [version]} (analyze-ci-tag) + lib (build-shared/lib-artifact-name)] + (status/line :head "Informing cljdoc of %s version %s" lib version) + (assert-on-ci) + (let [exit-code (-> (t/shell {:continue true} + "curl" "-X" "POST" + "-d" (str "project=" lib) + "-d" (str "version=" version) + "https://cljdoc.org/api/request-build2") + :exit)] + (when (not (zero? exit-code)) + (status/line :warn (str "Informing cljdoc did not seem to work, exited with " exit-code)))))) diff --git a/script/download_deps.clj b/script/download_deps.clj new file mode 100644 index 00000000..72c29440 --- /dev/null +++ b/script/download_deps.clj @@ -0,0 +1,23 @@ +(ns download-deps + (:require [babashka.tasks :as t] + [clojure.edn :as edn] + [lread.status-line :as status])) + +;; clojure has a -P command, but to bring down all deps we need to specify all aliases +;; bb deps will be brought down just from running bb (which assumedly is how this code is run) + +(defn -main [& _args] + (let [aliases (->> "deps.edn" + slurp + edn/read-string + :aliases + keys)] + ;; one at a time because aliases with :replace-deps will... well... you know. + (status/line :detail "Bring down default deps") + (t/clojure "-P") + (doseq [a aliases] + (status/line :detail "Bring down deps for alias: %s" a) + (t/clojure "-P" (str "-M" a))))) + +(when (= *file* (System/getProperty "babashka.file")) + (apply -main *command-line-args*)) diff --git a/bb/lint.clj b/script/lint.clj similarity index 96% rename from bb/lint.clj rename to script/lint.clj index d70b5934..4fe5545d 100644 --- a/bb/lint.clj +++ b/script/lint.clj @@ -50,7 +50,7 @@ (status/line :head "clj-kondo: linting") (let [{:keys [exit]} (t/clojure {:continue true} - "-M:clj-kondo --lint src test bb deps.edn bb.edn")] + "-M:clj-kondo --lint src test build script deps.edn bb.edn")] (cond (= 2 exit) (status/die exit "clj-kondo found one or more lint errors") (= 3 exit) (status/die exit "clj-kondo found one or more lint warnings") diff --git a/script/publish.clj b/script/publish.clj new file mode 100644 index 00000000..f4764e35 --- /dev/null +++ b/script/publish.clj @@ -0,0 +1,216 @@ +(ns publish + "Publish work that happens locally on a maintainer's work" + (:require [babashka.tasks :as t] + [build-shared] + [clojure.string :as string] + [lread.status-line :as status] + [version-clj.core :as v])) + +;; Note to lurkers: doc updates are geared to AsciiDoc files. + +(def github-coords "clj-commons/clj-http-lite") +(def changelog-fname "CHANGELOG.adoc") +(def user-guide-fname "doc/01-user-guide.adoc") +;; this project started with "Release-" but we prefer "v" as a version tag prefix +(def legacy-version-tag-prefix "Release-") + +(defn- raw-tags[] + (->> (t/shell {:out :string} + "git ls-remote --tags --refs") + :out + string/split-lines)) + +(defn- parse-raw-tag [raw-tag-line] + (let [pattern (re-pattern (str "refs/tags/((?:" + legacy-version-tag-prefix "|" + build-shared/version-tag-prefix ")(\\d+\\..*))"))] + (some->> (re-find pattern raw-tag-line) + rest + (zipmap [:tag :version])))) + +(defn- most-recent-tag [parsed-tags] + (->> parsed-tags + (sort-by :version v/version-compare) + reverse + first + :tag)) + +(defn last-release-tag [] + (->> (raw-tags) + (keep parse-raw-tag) + (most-recent-tag))) + +(defn- master-branch? [] + (let [current-branch (->> (t/shell {:out :string} "git rev-parse --abbrev-ref HEAD") + :out + string/trim)] + (= "master" current-branch))) + +(defn- uncommitted-code? [] + (-> (t/shell {:out :string} + "git status --porcelain") + :out + string/trim + seq)) + +(defn- unpushed-commits? [] + (let [{:keys [exit :out]} (t/shell {:continue true :out :string} + "git cherry -v")] + (if (zero? exit) + (-> out string/trim seq) + (status/die 1 "Failed to check for unpushed commits, are you on an unpushed branch?")))) + +(defn- analyze-changelog + "Certainly not fool proof, but should help for common mistakes" + [] + (let [content (slurp changelog-fname) + valid-attrs ["[minor breaking]" "[breaking]"] + [_ attr content :as match] (re-find #"(?ims)^== Unreleased ?(.*?)$(.*?)(== v\d|\z)" content)] + (if (not match) + [{:error :section-missing}] + (cond-> [] + (and attr + (not (string/blank? attr)) + (not (contains? (set valid-attrs) attr))) + (conj {:error :suffix-invalid :valid-attrs valid-attrs :found attr}) + + ;; without any words of a reasonable min length, we consider section blank + (not (re-find #"(?m)[\p{L}]{3,}" content)) + (conj {:error :content-missing}))))) + +(defn- release-checks [] + (let [changelog-findings (reduce (fn [acc n] (assoc acc (:error n) n)) + {} + (analyze-changelog))] + [{:check "on master branch" + :result (if (master-branch?) :pass :fail)} + {:check "no uncommitted code" + :result (if (uncommitted-code?) :fail :pass)} + {:check "no unpushed commits" + :result (if (unpushed-commits?) :fail :pass)} + {:check "changelog has unreleased section" + :result (if (:section-missing changelog-findings) :fail :pass)} + {:check "changelog unreleased section attributes valid" + :result (cond + (:section-missing changelog-findings) :skip + (:suffix-invalid changelog-findings) :fail + :else :pass) + :msg (when-let [{:keys [valid-attrs found]} (:suffix-invalid changelog-findings)] + (format "expected attributes to absent or one of %s, but found: %s" (string/join ", " valid-attrs) found))} + {:check "changelog unreleased section has content" + :result (cond + (:section-missing changelog-findings) :skip + (:content-missing changelog-findings) :fail + :else :pass)}])) + +(defn- bump-version! + "bump version stored in deps.edn" + [] + (t/shell "bb neil version patch --no-tag")) + +(defn- update-file! [fname desc match replacement] + (let [old-content (slurp fname) + new-content (string/replace-first old-content match replacement)] + (if (= old-content new-content) + (status/die 1 "Expected to %s in %s" desc fname) + (spit fname new-content)))) + +(defn- update-user-guide! [version] + (status/line :detail "Applying version %s to user guide" version) + (update-file! user-guide-fname + "update :lib-version: adoc attribute" + #"(?m)^(:lib-version: )(.*)$" + (str "$1" version))) + +(defn- yyyy-mm-dd-now-utc [] + (-> (java.time.Instant/now) str (subs 0 10))) + +(defn- update-changelog! [version release-tag last-release-tag] + (status/line :detail "Applying version %s to changelog" version) + (update-file! changelog-fname + "update unreleased header" + #"(?ims)^== Unreleased(.*?)($.*?)(== v\d|\z)" + (str + ;; add Unreleased section for next released + "== Unreleased\n\n" + ;; replace "Unreleased" with actual version + "== v" version + ;; followed by any attributes + "$1" + ;; followed by datestamp (local time is fine) + (str " - " (yyyy-mm-dd-now-utc)) + ;; followed by an AsciiDoc anchor for easy referencing + (str " [[v" version "]]") + ;; followed by section content + "$2" + ;; followed by link to commit log + (when last-release-tag + (str + "https://github.com/" github-coords "/compare/" + last-release-tag + "\\\\..." ;; single backslash is escape for AsciiDoc + release-tag + "[commit log]\n\n")) + ;; followed by next section indicator + "$3"))) + +(defn- commit-changes! [version] + (t/shell "git add deps.edn" changelog-fname user-guide-fname) + (t/shell "git commit -m" (str "publish: apply version " version))) + +(defn- tag! [tag version] + (t/shell "git tag" tag "-m" (str "For release: " version))) + +(defn- push! [] + (t/shell "git push")) + +(defn- push-tag! [tag] + (t/shell "git push origin" tag)) + +;; task entry points + +(defn pubcheck [] + (status/line :head "Performing publish checks") + (let [check-results (release-checks) + passed? (every? #(= :pass (:result %)) check-results)] + (doseq [{:keys [check result msg]} check-results] + (status/line :detail "%s %s" + (case result + :pass "✓" + :fail "x" + :skip "~") + check) + (when msg + (status/line :detail " > %s" msg))) + (when (not passed?) + (status/die 1 "Release checks failed")))) + +(defn -main [& _args] + (pubcheck) + (status/line :head "Calculating versions") + (bump-version!) + (let [last-release-tag (last-release-tag) + version (build-shared/lib-version) + release-tag (build-shared/version->tag version)] + (status/line :detail "Release version: %s" version) + (status/line :detail "Release tag: %s" release-tag) + (status/line :detail "Last release tag: %s" last-release-tag) + (status/line :head "Updating docs") + (update-user-guide! version) + (update-changelog! version release-tag last-release-tag) + (status/line :head "Committing changes") + (commit-changes! version) + (status/line :head "Tagging & pushing") + (tag! release-tag version) + (push!) + (push-tag! release-tag) + (status/line :detail "\nLocal work done.") + (status/line :head "Remote work") + (status/line :detail "The remainging work will be triggered by the release tag on CI:") + (status/line :detail "- Publish a release jar to clojars") + (status/line :detail "- Create a GitHub release") + (status/line :detail "- Inform cljdoc of release"))) + +;; default action when executing file directly +(when (= *file* (System/getProperty "babashka.file")) + (apply -main *command-line-args*)) diff --git a/bb/test_jvm.clj b/script/test_jvm.clj similarity index 100% rename from bb/test_jvm.clj rename to script/test_jvm.clj diff --git a/version.edn b/version.edn deleted file mode 100644 index 4ebec580..00000000 --- a/version.edn +++ /dev/null @@ -1 +0,0 @@ -"0.4" From 1586f8d3a541b5482e6eaf41fdfeeca2932a306c Mon Sep 17 00:00:00 2001 From: lread Date: Thu, 29 Sep 2022 17:34:45 -0400 Subject: [PATCH 127/143] publish: apply version 1.0.13 --- CHANGELOG.adoc | 4 ++++ deps.edn | 2 +- doc/01-user-guide.adoc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5580886e..a6af8d6e 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -13,6 +13,8 @@ A release with known breaking changes is marked with: // (adjust these in publish.clj as you see fit) == Unreleased +== v1.0.13 - 2022-09-29 [[v1.0.13]] + * If specified, request’s body encoding is now applied, else defaults to UTF-8 (https://github.com/clj-commons/clj-http-lite/issues/18[#18]) (https://github.com/lread[@lread]) * User info from request URL now applied to basic auth (https://github.com/clj-commons/clj-http-lite/issues/34[#34]) (https://github.com/lread[@lread]) * Nested query and form parameters are now automatically flattened (https://github.com/clj-commons/clj-http-lite/issues/43[#43]) (https://github.com/lread[@lread]) @@ -25,6 +27,8 @@ A release with known breaking changes is marked with: ** Automated CI testing added for Windows (https://github.com/clj-commons/clj-http-lite/issues/21[#21]) (https://github.com/lread[@lread]) ** Babashka now exercised under full test suite (https://github.com/clj-commons/clj-http-lite/issues/48[#48]) (https://github.com/lread[@lread]) +https://github.com/clj-commons/clj-http-lite/compare/Release-0.4.392\...v1.0.13[commit log] + == v0.4.392 - 2021-11-18 * Support self-signed certificates via `:insecure? true` option diff --git a/deps.edn b/deps.edn index 211c233e..d718a048 100644 --- a/deps.edn +++ b/deps.edn @@ -3,7 +3,7 @@ :aliases {;; we use babashka/neil for project attributes ;; publish workflow references these values (and automatically bumps patch) - :neil {:project {:version "1.0.12" + :neil {:project {:version "1.0.13" :name org.clj-commons/clj-http-lite}} :1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index 214a6a70..e095cda6 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -2,7 +2,7 @@ :toclevels: 5 :toc: // DO NOT EDIT: the lib-version parameter is automatically updated by bb publish -:lib-version: 0.4.392 +:lib-version: 1.0.13 == Introduction Clj-http-lite is a Clojure, Babashka and GraalVM compatible liteweight subset of http://github.com/dakrone/clj-http[clj-http]. From 0d8bc580a158d5a6104943acec3e1fba6fdd2724 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 29 Sep 2022 18:19:56 -0400 Subject: [PATCH 128/143] docs: user-guide: minor formatting fix [skip ci] --- doc/01-user-guide.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index e095cda6..5515613a 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -16,7 +16,7 @@ Clj-http-lite is a Clojure, Babashka and GraalVM compatible liteweight subset of * No multipart form uploads * No persistent connection support * Fewer options -* namespace rename `clj-http.*` -> `clj-http.lite.*` +* namespace rename `+clj-http.*+` -> `+clj-http.lite.*+` Like its namesake, clj-http-lite is light and simple, but ping us if there is some clj-http feature you’d like to see in clj-http-lite. We can discuss. From 3e3b65d0e808b59ae11ed741322a27faf59f266c Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 15 May 2023 10:53:11 -0400 Subject: [PATCH 129/143] docs: update interesting alternatives (#72) Add org.babashka/http-client State min jdk version for other alternatives. Add note on babashka.curl. --- doc/01-user-guide.adoc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index 5515613a..4da1a8dc 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -41,14 +41,15 @@ Maybe clj-http-lite is not your cup of tea? Some alternatives to explore: Clojure based: -* http://github.com/dakrone/clj-http[clj-http] - heavier than clj-http-lite, but has many more features +* http://github.com/dakrone/clj-http[clj-http] (jdk8+) - heavier than clj-http-lite, but has many more features Babashka compatible: -* https://github.com/schmee/java-http-clj[java-http-clj] - Clojure wrapper for java.net.http with async, HTTP/2 and WebSockets -* https://github.com/http-kit/http-kit[http-kit] - minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support -* https://github.com/gnarroway/hato[hato] - An HTTP client for Clojure, wrapping JDK 11's HttpClient -* https://github.com/babashka/babashka.curl[babashka.curl] - A tiny curl wrapper via idiomatic Clojure, inspired by clj-http, Ring and friends +* https://github.com/babashka/http-client[org.babashka/http-client] (jdk11+) - HTTP client for Clojure and Babashka built on java.net.http +* https://github.com/schmee/java-http-clj[java-http-clj] (jdk11+) - Clojure wrapper for java.net.http with async, HTTP/2 and WebSockets +* https://github.com/http-kit/http-kit[http-kit] (jdk8+?) - minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support +* https://github.com/gnarroway/hato[hato] (jdk11+) - An HTTP client for Clojure, wrapping JDK 11's HttpClient +* https://github.com/babashka/babashka.curl[babashka.curl] (jdk8+) - A tiny curl wrapper via idiomatic Clojure, inspired by clj-http, Ring and friends (now mostly replaced by org.babashka/http-client) == Installation From 5d5f836e70dc0e5946d2b0a66b5292e8df22b12e Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 15 May 2023 10:54:37 -0400 Subject: [PATCH 130/143] docs: minor tweak [skip ci] (#73) --- doc/01-user-guide.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index 4da1a8dc..e2052074 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -45,11 +45,11 @@ Clojure based: Babashka compatible: -* https://github.com/babashka/http-client[org.babashka/http-client] (jdk11+) - HTTP client for Clojure and Babashka built on java.net.http +* https://github.com/babashka/http-client[babashka/http-client] (jdk11+) - HTTP client for Clojure and Babashka built on java.net.http * https://github.com/schmee/java-http-clj[java-http-clj] (jdk11+) - Clojure wrapper for java.net.http with async, HTTP/2 and WebSockets * https://github.com/http-kit/http-kit[http-kit] (jdk8+?) - minimalist, event-driven, high-performance Clojure HTTP server/client library with WebSocket and asynchronous support * https://github.com/gnarroway/hato[hato] (jdk11+) - An HTTP client for Clojure, wrapping JDK 11's HttpClient -* https://github.com/babashka/babashka.curl[babashka.curl] (jdk8+) - A tiny curl wrapper via idiomatic Clojure, inspired by clj-http, Ring and friends (now mostly replaced by org.babashka/http-client) +* https://github.com/babashka/babashka.curl[babashka.curl] (jdk8+) - A tiny curl wrapper via idiomatic Clojure, inspired by clj-http, Ring and friends (now mostly replaced by babashka/http-client) == Installation From 70c34e4f8d5abb5f68e3e94441f2dadd819c4f11 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 28 Jul 2023 16:11:55 -0400 Subject: [PATCH 131/143] Create ORIGINATOR Credit hiredman as creator of clj-http-lite --- ORIGINATOR | 1 + 1 file changed, 1 insertion(+) create mode 100644 ORIGINATOR diff --git a/ORIGINATOR b/ORIGINATOR new file mode 100644 index 00000000..b5121299 --- /dev/null +++ b/ORIGINATOR @@ -0,0 +1 @@ +@hiredman From 492c701a1318a1c962f497bd1db464b6ff242df6 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 13 Mar 2024 11:58:03 -0400 Subject: [PATCH 132/143] maint: bump deps (ci and test only) (#75) Of note: - turfed: bb no longer needs https://github.com/babashka/tools.namespace to run tests - bump ring-jetty-adapter to latest version that works on jdk8 - now also testing against clojure 1.12 - now also testing against jdk 21 --- .clj-kondo/http-kit/http-kit/config.edn | 3 +++ .../http-kit/httpkit/with_channel.clj | 16 ++++++++++++ .github/workflows/publish.yml | 2 +- .github/workflows/shared-setup/action.yml | 7 +++--- .github/workflows/tests.yml | 12 ++++----- bb.edn | 9 +++---- deps.edn | 25 ++++++++++--------- doc/01-user-guide.adoc | 2 +- script/test_jvm.clj | 2 +- 9 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 .clj-kondo/http-kit/http-kit/config.edn create mode 100644 .clj-kondo/http-kit/http-kit/httpkit/with_channel.clj diff --git a/.clj-kondo/http-kit/http-kit/config.edn b/.clj-kondo/http-kit/http-kit/config.edn new file mode 100644 index 00000000..e9dbcd8a --- /dev/null +++ b/.clj-kondo/http-kit/http-kit/config.edn @@ -0,0 +1,3 @@ + +{:hooks + {:analyze-call {org.httpkit.server/with-channel httpkit.with-channel/with-channel}}} diff --git a/.clj-kondo/http-kit/http-kit/httpkit/with_channel.clj b/.clj-kondo/http-kit/http-kit/httpkit/with_channel.clj new file mode 100644 index 00000000..b429de89 --- /dev/null +++ b/.clj-kondo/http-kit/http-kit/httpkit/with_channel.clj @@ -0,0 +1,16 @@ +(ns httpkit.with-channel + (:require [clj-kondo.hooks-api :as api])) + +(defn with-channel [{node :node}] + (let [[request channel & body] (rest (:children node))] + (when-not (and request channel) (throw (ex-info "No request or channel provided" {}))) + (when-not (api/token-node? channel) (throw (ex-info "Missing channel argument" {}))) + (let [new-node + (api/list-node + (list* + (api/token-node 'let) + (api/vector-node [channel (api/vector-node [])]) + request + body))] + + {:node new-node}))) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8bd0e3ab..d7096276 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup uses: ./.github/workflows/shared-setup diff --git a/.github/workflows/shared-setup/action.yml b/.github/workflows/shared-setup/action.yml index f994f8c8..28c77347 100644 --- a/.github/workflows/shared-setup/action.yml +++ b/.github/workflows/shared-setup/action.yml @@ -14,7 +14,7 @@ runs: steps: - name: Clojure deps cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.m2/repository @@ -24,13 +24,13 @@ runs: restore-keys: cljdeps- - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: ${{ inputs.jdk }} - name: Install Clojure Tools - uses: DeLaGuardo/setup-clojure@9.5 + uses: DeLaGuardo/setup-clojure@12.5 with: cli: 'latest' bb: 'latest' @@ -44,6 +44,7 @@ runs: bb --version echo "clojure --version" clojure --version + - name: Download Clojure Dependencies shell: ${{ inputs.shell }} run: bb download-deps diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 98add901..c36421c0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v4 - name: Setup uses: ./.github/workflows/shared-setup @@ -29,14 +29,14 @@ jobs: fail-fast: false matrix: os: [{name: 'windows', shell: 'pwsh'}, {name: 'ubuntu', shell: 'bash'}] - clojure-version: ["1.8", "1.9", "1.10", "1.11"] - jdk: ['8', '11', '17'] + clojure-version: ["1.8", "1.9", "1.10", "1.11", "1.12"] + jdk: ['8', '11', '17', '21'] - name: ${{ matrix.os.name }} clj-${{ matrix.clojure-version }} jdk${{ matrix.java-version }} + name: ${{ matrix.os.name }} clj-${{ matrix.clojure-version }} jdk${{ matrix.jdk }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup uses: ./.github/workflows/shared-setup @@ -58,7 +58,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v4 - name: Setup uses: ./.github/workflows/shared-setup diff --git a/bb.edn b/bb.edn index b4b7c962..55647459 100644 --- a/bb.edn +++ b/bb.edn @@ -1,6 +1,6 @@ {:paths ["script" "build"] :deps {lread/status-line {:git/url "https://github.com/lread/status-line.git" - :sha "35ed39645038e81b42cb15ed6753b8462e60a06d"} + :sha "cf44c15f30ea3867227fa61ceb823e5e942c707f"} version-clj/version-clj {:mvn/version "2.0.2"}} :tasks {;; setup :requires ([babashka.fs :as fs] @@ -28,9 +28,7 @@ {:doc "Runs tests under babashka Clojure (recognizes cognitect test-runner args)" :extra-paths ["src" "test" "test-resources"] :extra-deps {io.github.cognitect-labs/test-runner - {:git/tag "v0.5.1" :git/sha "dfb30dd"} - org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace" - :git/sha "16b8c53174a5c9d89d6e0ce4128aa30b071aabdf"}} + {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :requires ([cognitect.test-runner :as tr]) :task (apply tr/-main *command-line-args*)} lint @@ -44,8 +42,7 @@ :task publish/-main} neil ;; let's not rely on a random version of neil {:doc "Pinned version of babashka/neil (used in scripting)" - :extra-deps {babashka/neil {:git/url "https://github.com/babashka/neil.git" - :sha "6fc58cc6a4253c2c15f05135f1610ab3d46d961f"}} + :extra-deps {io.github.babashka/neil {:git/tag "v0.2.63" :git/sha "076fb83"}} :task babashka.neil/-main} ;; hidden tasks, no need for folks to be trying these ci invoked tasks -ci-clojars-deploy diff --git a/deps.edn b/deps.edn index d718a048..e7f58d07 100644 --- a/deps.edn +++ b/deps.edn @@ -8,22 +8,23 @@ :1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} - :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.1"}}} + :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.2"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha9"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"} - slipset/deps-deploy {:mvn/version "0.2.0"}} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.0"} + slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] - :override-deps {org.clojure/clojure {:mvn/version "1.11.1"}} - :extra-deps {babashka/fs {:mvn/version "0.1.6"} - ring/ring-jetty-adapter {:mvn/version "1.9.5"} - ch.qos.logback/logback-classic {:mvn/version "1.2.11" + :override-deps {org.clojure/clojure {:mvn/version "1.11.2"}} + :extra-deps {babashka/fs {:mvn/version "0.5.20"} + ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 + ch.qos.logback/logback-classic {:mvn/version "1.5.3" :exclusions [org.slf4j/slf4j-api]} - org.slf4j/jcl-over-slf4j {:mvn/version "1.7.36"} - org.slf4j/jul-to-slf4j {:mvn/version "1.7.36"} - org.slf4j/log4j-over-slf4j {:mvn/version "1.7.36"}} + org.slf4j/jcl-over-slf4j {:mvn/version "2.0.12"} + org.slf4j/jul-to-slf4j {:mvn/version "2.0.12"} + org.slf4j/log4j-over-slf4j {:mvn/version "2.0.12"}} :exec-fn clj-http.lite.test-util.http-server/run} :test {:extra-paths ["test"] @@ -31,6 +32,6 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2022.08.03"}} - :override-deps {org.clojure/clojure {:mvn/version "1.11.1"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.03.13"}} + :override-deps {org.clojure/clojure {:mvn/version "1.11.2"}} :main-opts ["-m" "clj-kondo.main"]}}} diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index e2052074..bf1a410a 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -23,7 +23,7 @@ We can discuss. === Supported Environments [[supported-envs]] -* JDK 8, 11, 17 +* JDK 8, 11, 17, 21 * Clojure 1.8 runtime and above * Babashka current release * Windows, Linux, macOS diff --git a/script/test_jvm.clj b/script/test_jvm.clj index b66bbfa7..dddbab9c 100644 --- a/script/test_jvm.clj +++ b/script/test_jvm.clj @@ -4,7 +4,7 @@ [lread.status-line :as status])) (defn -main [& args] - (let [valid-clojure-versions ["1.8" "1.9" "1.10" "1.11"] + (let [valid-clojure-versions ["1.8" "1.9" "1.10" "1.11" "1.12"] spec {:clj-version {:ref "" :desc "The Clojure version to test against." From 3edc08a60a270298463290f3e45d9ce06df8d056 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 13 Mar 2024 12:00:03 -0400 Subject: [PATCH 133/143] doc: readme: minor typos [skip ci] --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index b6c529a7..076e3b0b 100644 --- a/README.adoc +++ b/README.adoc @@ -37,7 +37,7 @@ Don't see your project listed? Let us know, we'll be happy to include it! === Contributors -A big thank you to al the people who have contributed directly to clj-http-lite! +A big thank you to all the people who have contributed directly to clj-http-lite! * https://github.com/katox[@katox] * https://github.com/sattvik[@sattvik] @@ -66,6 +66,6 @@ Don't see your name? Our apologies! Let us know and we'll add you in. * https://github.com/borkdude[@borkdude] == License -We respect the original license at time of forking from clj-http: +We respect the original license at the time of forking from clj-http: Released under the MIT License: http://www.opensource.org/licenses/mit-license.php From 03e351ddd9b44bb98e9dfaa7731e7b99019ce935 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 13 Mar 2024 12:03:44 -0400 Subject: [PATCH 134/143] doc: readme: fix tests badge [skip ci] --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 076e3b0b..deb4cce8 100644 --- a/README.adoc +++ b/README.adoc @@ -5,7 +5,7 @@ // Badges link:{url-doc}[image:https://cljdoc.org/badge/{project-mvn-coords}[Cljdoc]] -https://github.com/{project-src-coords}/actions/workflows/ci.yml[image:https://github.com/{project-src-coords}/workflows/Tests/badge.svg[GitHub Actions tests]] +https://github.com/{project-src-coords}/actions/workflows/tests.yml[image:https://github.com/{project-src-coords}/workflows/tests/badge.svg[GitHub Actions tests]] https://clojars.org/{project-mvn-coords}[image:https://img.shields.io/clojars/v/{project-mvn-coords}.svg[Clojars]] https://babashka.org[image:https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg[bb compatible]] https://clojurians.slack.com/archives/C03UZ1Y8414[image:https://img.shields.io/badge/slack-join_chat-brightgreen.svg[Join chat]] From 40fc7181a4d1a315e3e70ffdf17ee84aefb97839 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 8 May 2024 14:11:24 -0400 Subject: [PATCH 135/143] test & dev & ci: bump deps, add outdated task (#76) Bump test and build deps (including latest clojure 11 and 12-alpha). Added an `outdated` task to add some antq configuration to document/express that we don't want to move to any deps that are not jdk8 compatible. Checked in some 3rd party lib lint config clj-kondo found. --- .clj-kondo/taoensso/encore/config.edn | 1 + .../taoensso/encore/taoensso/encore.clj | 16 ++++++++++ bb.edn | 5 +++- deps.edn | 30 ++++++++++++------- 4 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 .clj-kondo/taoensso/encore/config.edn create mode 100644 .clj-kondo/taoensso/encore/taoensso/encore.clj diff --git a/.clj-kondo/taoensso/encore/config.edn b/.clj-kondo/taoensso/encore/config.edn new file mode 100644 index 00000000..7b0ff3c2 --- /dev/null +++ b/.clj-kondo/taoensso/encore/config.edn @@ -0,0 +1 @@ +{:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}} diff --git a/.clj-kondo/taoensso/encore/taoensso/encore.clj b/.clj-kondo/taoensso/encore/taoensso/encore.clj new file mode 100644 index 00000000..7f6d30ac --- /dev/null +++ b/.clj-kondo/taoensso/encore/taoensso/encore.clj @@ -0,0 +1,16 @@ +(ns taoensso.encore + (:require + [clj-kondo.hooks-api :as hooks])) + +(defn defalias [{:keys [node]}] + (let [[sym-raw src-raw] (rest (:children node)) + src (if src-raw src-raw sym-raw) + sym (if src-raw + sym-raw + (symbol (name (hooks/sexpr src))))] + {:node (with-meta + (hooks/list-node + [(hooks/token-node 'def) + (hooks/token-node (hooks/sexpr sym)) + (hooks/token-node (hooks/sexpr src))]) + (meta src))})) diff --git a/bb.edn b/bb.edn index 55647459..fe7b296d 100644 --- a/bb.edn +++ b/bb.edn @@ -34,6 +34,9 @@ lint {:doc "[--rebuild] Lint source code" :task lint/-main} + outdated + {:doc "Report on outdated dependencies" + :task (clojure {:continue true} "-M:outdated")} pubcheck {:doc "run only publish checks (without publishing)" :task publish/pubcheck} @@ -42,7 +45,7 @@ :task publish/-main} neil ;; let's not rely on a random version of neil {:doc "Pinned version of babashka/neil (used in scripting)" - :extra-deps {io.github.babashka/neil {:git/tag "v0.2.63" :git/sha "076fb83"}} + :extra-deps {io.github.babashka/neil {:git/tag "v0.3.65" :git/sha "9a79582"}} :task babashka.neil/-main} ;; hidden tasks, no need for folks to be trying these ci invoked tasks -ci-clojars-deploy diff --git a/deps.edn b/deps.edn index e7f58d07..9da154a6 100644 --- a/deps.edn +++ b/deps.edn @@ -8,23 +8,23 @@ :1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} - :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.2"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha9"}}} + :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha11"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:mvn/version "0.10.0"} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.3"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] - :override-deps {org.clojure/clojure {:mvn/version "1.11.2"}} + :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :extra-deps {babashka/fs {:mvn/version "0.5.20"} ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 - ch.qos.logback/logback-classic {:mvn/version "1.5.3" + ch.qos.logback/logback-classic {:mvn/version "1.3.14" :exclusions [org.slf4j/slf4j-api]} - org.slf4j/jcl-over-slf4j {:mvn/version "2.0.12"} - org.slf4j/jul-to-slf4j {:mvn/version "2.0.12"} - org.slf4j/log4j-over-slf4j {:mvn/version "2.0.12"}} + org.slf4j/jcl-over-slf4j {:mvn/version "2.0.13"} + org.slf4j/jul-to-slf4j {:mvn/version "2.0.13"} + org.slf4j/log4j-over-slf4j {:mvn/version "2.0.13"}} :exec-fn clj-http.lite.test-util.http-server/run} :test {:extra-paths ["test"] @@ -33,5 +33,15 @@ :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.03.13"}} - :override-deps {org.clojure/clojure {:mvn/version "1.11.2"}} - :main-opts ["-m" "clj-kondo.main"]}}} + :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} + :main-opts ["-m" "clj-kondo.main"]} + :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1201"} + org.clojure/clojure {:mvn/version "1.11.3"} + org.slf4j/slf4j-simple {:mvn/version "2.0.13"} ;; to rid ourselves of logger warnings + } + :main-opts ["-m" "antq.core" + "--exclude=ch.qos.logback/logback-classic@1.4.x" ;; requires min jdk 11, we are jdk8 compatible + "--exclude=ch.qos.logback/logback-classic@1.5.x" ;; requires min jdk 11, we are jdk8 compatible + "--exclude=ring/ring-jetty-adapter@1.11.x" ;; requires jdk 11, we are jdk8 compatible + "--exclude=ring/ring-jetty-adapter@1.12.x" ;; requires jdk 11, we are jdk8 compatible + ]}}} From 2073fbe350de187774b7a17a5b545c831bfd6d86 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 23 May 2024 16:22:54 -0400 Subject: [PATCH 136/143] test & ci: bump deps! (#77) Highlights!: New clj-kondo! New clojure 1.12-alpha! --- deps.edn | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index 9da154a6..6d6afd42 100644 --- a/deps.edn +++ b/deps.edn @@ -9,7 +9,7 @@ :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha11"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha12"}}} :build {:extra-paths ["build"] :deps {io.github.clojure/tools.build {:mvn/version "0.10.3"} @@ -18,7 +18,7 @@ :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} - :extra-deps {babashka/fs {:mvn/version "0.5.20"} + :extra-deps {babashka/fs {:mvn/version "0.5.21"} ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 ch.qos.logback/logback-classic {:mvn/version "1.3.14" :exclusions [org.slf4j/slf4j-api]} @@ -32,7 +32,7 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.03.13"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.05.22"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1201"} From ee3febfe3b842c9d0e24729f0943165a7f8aaeb1 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 20 Jun 2024 10:40:21 -0400 Subject: [PATCH 137/143] test & ci: bump deps (#78) Of note: First clojure 1.12 beta! --- deps.edn | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.edn b/deps.edn index 6d6afd42..5b408901 100644 --- a/deps.edn +++ b/deps.edn @@ -9,10 +9,10 @@ :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-alpha12"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-beta1"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:mvn/version "0.10.3"} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.4"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests @@ -32,7 +32,7 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.05.22"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.05.24"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1201"} From a7bbba37522d0410831a5719a6fceaa3af90463d Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 29 Jul 2024 18:55:36 -0400 Subject: [PATCH 138/143] test & ci: bump deps, tweak pubcheck (#79) Of note: - clojure 1.12 beta2! - bb `pubcheck` task can now run checks on unpushed branch --- bb.edn | 2 +- deps.edn | 6 +++--- script/publish.clj | 11 +++++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bb.edn b/bb.edn index fe7b296d..ec4722b0 100644 --- a/bb.edn +++ b/bb.edn @@ -45,7 +45,7 @@ :task publish/-main} neil ;; let's not rely on a random version of neil {:doc "Pinned version of babashka/neil (used in scripting)" - :extra-deps {io.github.babashka/neil {:git/tag "v0.3.65" :git/sha "9a79582"}} + :extra-deps {io.github.babashka/neil {:git/tag "v0.3.67" :git/sha "054ca51"}} :task babashka.neil/-main} ;; hidden tasks, no need for folks to be trying these ci invoked tasks -ci-clojars-deploy diff --git a/deps.edn b/deps.edn index 5b408901..bb22b1b7 100644 --- a/deps.edn +++ b/deps.edn @@ -9,10 +9,10 @@ :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-beta1"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-beta2"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:mvn/version "0.10.4"} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.5"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests @@ -35,7 +35,7 @@ :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.05.24"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} - :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1201"} + :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1206"} org.clojure/clojure {:mvn/version "1.11.3"} org.slf4j/slf4j-simple {:mvn/version "2.0.13"} ;; to rid ourselves of logger warnings } diff --git a/script/publish.clj b/script/publish.clj index f4764e35..51786b4e 100644 --- a/script/publish.clj +++ b/script/publish.clj @@ -53,12 +53,15 @@ string/trim seq)) +(defn- local-branch? [] + (let [{:keys [exit]} (t/shell {:continue true :out :string :err :out} + "git rev-parse --symbolic-full-name @{u}")] + (not (zero? exit)))) + (defn- unpushed-commits? [] (let [{:keys [exit :out]} (t/shell {:continue true :out :string} "git cherry -v")] - (if (zero? exit) - (-> out string/trim seq) - (status/die 1 "Failed to check for unpushed commits, are you on an unpushed branch?")))) + (and (zero? exit) (-> out string/trim seq)))) (defn- analyze-changelog "Certainly not fool proof, but should help for common mistakes" @@ -87,7 +90,7 @@ {:check "no uncommitted code" :result (if (uncommitted-code?) :fail :pass)} {:check "no unpushed commits" - :result (if (unpushed-commits?) :fail :pass)} + :result (if (or (local-branch?) (unpushed-commits?)) :fail :pass)} {:check "changelog has unreleased section" :result (if (:section-missing changelog-findings) :fail :pass)} {:check "changelog unreleased section attributes valid" From 742f267f832ad9c33e916d296ea37e38b111bcd4 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Thu, 5 Sep 2024 16:51:38 -0400 Subject: [PATCH 139/143] test & ci: bump deps (#80) Of note: - clojure 1.12.0! woot! - new version of clj-kondo - we can now build cache and copy configs in one step --- bb.edn | 2 +- deps.edn | 16 ++++++++-------- script/lint.clj | 8 +++----- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/bb.edn b/bb.edn index ec4722b0..7c5be060 100644 --- a/bb.edn +++ b/bb.edn @@ -1,7 +1,7 @@ {:paths ["script" "build"] :deps {lread/status-line {:git/url "https://github.com/lread/status-line.git" :sha "cf44c15f30ea3867227fa61ceb823e5e942c707f"} - version-clj/version-clj {:mvn/version "2.0.2"}} + version-clj/version-clj {:mvn/version "2.0.3"}} :tasks {;; setup :requires ([babashka.fs :as fs] [clojure.string :as string] diff --git a/deps.edn b/deps.edn index bb22b1b7..01362de3 100644 --- a/deps.edn +++ b/deps.edn @@ -9,7 +9,7 @@ :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0-beta2"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0"}}} :build {:extra-paths ["build"] :deps {io.github.clojure/tools.build {:mvn/version "0.10.5"} @@ -18,13 +18,13 @@ :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} - :extra-deps {babashka/fs {:mvn/version "0.5.21"} + :extra-deps {babashka/fs {:mvn/version "0.5.22"} ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 ch.qos.logback/logback-classic {:mvn/version "1.3.14" :exclusions [org.slf4j/slf4j-api]} - org.slf4j/jcl-over-slf4j {:mvn/version "2.0.13"} - org.slf4j/jul-to-slf4j {:mvn/version "2.0.13"} - org.slf4j/log4j-over-slf4j {:mvn/version "2.0.13"}} + org.slf4j/jcl-over-slf4j {:mvn/version "2.0.16"} + org.slf4j/jul-to-slf4j {:mvn/version "2.0.16"} + org.slf4j/log4j-over-slf4j {:mvn/version "2.0.16"}} :exec-fn clj-http.lite.test-util.http-server/run} :test {:extra-paths ["test"] @@ -32,12 +32,12 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.05.24"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.08.29"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} - :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.8.1206"} + :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.9.1221"} org.clojure/clojure {:mvn/version "1.11.3"} - org.slf4j/slf4j-simple {:mvn/version "2.0.13"} ;; to rid ourselves of logger warnings + org.slf4j/slf4j-simple {:mvn/version "2.0.16"} ;; to rid ourselves of logger warnings } :main-opts ["-m" "antq.core" "--exclude=ch.qos.logback/logback-classic@1.4.x" ;; requires min jdk 11, we are jdk8 compatible diff --git a/script/lint.clj b/script/lint.clj index 4fe5545d..a6495955 100644 --- a/script/lint.clj +++ b/script/lint.clj @@ -23,10 +23,8 @@ with-out-str string/trim) bb-cp (bbcp/get-classpath)] - (status/line :detail "- copying configs") - (t/clojure "-M:clj-kondo --skip-lint --copy-configs --lint" clj-cp bb-cp) - (status/line :detail "- creating cache") - (t/clojure "-M:clj-kondo --dependencies --lint" clj-cp bb-cp))) + (status/line :detail "- copying lib configs and creating cache") + (t/clojure "-M:clj-kondo --skip-lint --copy-configs --dependencies --lint" clj-cp bb-cp))) (defn- check-cache [{:keys [rebuild]}] (status/line :head "clj-kondo: cache check") @@ -50,7 +48,7 @@ (status/line :head "clj-kondo: linting") (let [{:keys [exit]} (t/clojure {:continue true} - "-M:clj-kondo --lint src test build script deps.edn bb.edn")] + "-M:clj-kondo --parallel --lint src test build script deps.edn bb.edn")] (cond (= 2 exit) (status/die exit "clj-kondo found one or more lint errors") (= 3 exit) (status/die exit "clj-kondo found one or more lint warnings") From 7645928b131ce79064bc2514a6e5d253475f1958 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Wed, 26 Mar 2025 21:19:16 +0000 Subject: [PATCH 140/143] test & ci: bump deps (#81) Of note: - bumping kondo uncovered redundant nested str call in script, fixed! - moved clj-kondo imports from the legacy .clj-kondo/ dir to current recommended .clj-kondo/imports dir - added jdk24 to ci test matrix --- .../{ => imports}/babashka/fs/config.edn | 0 .../http-kit/http-kit/config.edn | 0 .../http-kit/httpkit/with_channel.clj | 0 .../lread/status-line/config.edn | 0 .../rewrite-clj/rewrite-clj/config.edn | 0 .clj-kondo/imports/taoensso/encore/config.edn | 5 ++ .../taoensso/encore/taoensso/encore.clj | 51 +++++++++++++++++++ .clj-kondo/taoensso/encore/config.edn | 1 - .../taoensso/encore/taoensso/encore.clj | 16 ------ .github/workflows/shared-setup/action.yml | 2 +- .github/workflows/tests.yml | 4 +- bb.edn | 2 +- deps.edn | 20 ++++---- script/publish.clj | 4 +- 14 files changed, 72 insertions(+), 33 deletions(-) rename .clj-kondo/{ => imports}/babashka/fs/config.edn (100%) rename .clj-kondo/{ => imports}/http-kit/http-kit/config.edn (100%) rename .clj-kondo/{ => imports}/http-kit/http-kit/httpkit/with_channel.clj (100%) rename .clj-kondo/{ => imports}/lread/status-line/config.edn (100%) rename .clj-kondo/{ => imports}/rewrite-clj/rewrite-clj/config.edn (100%) create mode 100644 .clj-kondo/imports/taoensso/encore/config.edn create mode 100644 .clj-kondo/imports/taoensso/encore/taoensso/encore.clj delete mode 100644 .clj-kondo/taoensso/encore/config.edn delete mode 100644 .clj-kondo/taoensso/encore/taoensso/encore.clj diff --git a/.clj-kondo/babashka/fs/config.edn b/.clj-kondo/imports/babashka/fs/config.edn similarity index 100% rename from .clj-kondo/babashka/fs/config.edn rename to .clj-kondo/imports/babashka/fs/config.edn diff --git a/.clj-kondo/http-kit/http-kit/config.edn b/.clj-kondo/imports/http-kit/http-kit/config.edn similarity index 100% rename from .clj-kondo/http-kit/http-kit/config.edn rename to .clj-kondo/imports/http-kit/http-kit/config.edn diff --git a/.clj-kondo/http-kit/http-kit/httpkit/with_channel.clj b/.clj-kondo/imports/http-kit/http-kit/httpkit/with_channel.clj similarity index 100% rename from .clj-kondo/http-kit/http-kit/httpkit/with_channel.clj rename to .clj-kondo/imports/http-kit/http-kit/httpkit/with_channel.clj diff --git a/.clj-kondo/lread/status-line/config.edn b/.clj-kondo/imports/lread/status-line/config.edn similarity index 100% rename from .clj-kondo/lread/status-line/config.edn rename to .clj-kondo/imports/lread/status-line/config.edn diff --git a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn b/.clj-kondo/imports/rewrite-clj/rewrite-clj/config.edn similarity index 100% rename from .clj-kondo/rewrite-clj/rewrite-clj/config.edn rename to .clj-kondo/imports/rewrite-clj/rewrite-clj/config.edn diff --git a/.clj-kondo/imports/taoensso/encore/config.edn b/.clj-kondo/imports/taoensso/encore/config.edn new file mode 100644 index 00000000..62a26ca0 --- /dev/null +++ b/.clj-kondo/imports/taoensso/encore/config.edn @@ -0,0 +1,5 @@ +{:hooks + {:analyze-call + {taoensso.encore/defalias taoensso.encore/defalias + taoensso.encore/defn-cached taoensso.encore/defn-cached + taoensso.encore/defonce taoensso.encore/defonce}}} diff --git a/.clj-kondo/imports/taoensso/encore/taoensso/encore.clj b/.clj-kondo/imports/taoensso/encore/taoensso/encore.clj new file mode 100644 index 00000000..5af6de91 --- /dev/null +++ b/.clj-kondo/imports/taoensso/encore/taoensso/encore.clj @@ -0,0 +1,51 @@ +(ns taoensso.encore + "I don't personally use clj-kondo, so these hooks are + kindly authored and maintained by contributors. + PRs very welcome! - Peter Taoussanis" + (:refer-clojure :exclude [defonce]) + (:require + [clj-kondo.hooks-api :as hooks])) + +(defn defalias + [{:keys [node]}] + (let [[sym-raw src-raw] (rest (:children node)) + src (or src-raw sym-raw) + sym (if src-raw sym-raw (symbol (name (hooks/sexpr src))))] + {:node + (with-meta + (hooks/list-node + [(hooks/token-node 'def) + (hooks/token-node (hooks/sexpr sym)) + (hooks/token-node (hooks/sexpr src))]) + (meta src))})) + +(defn defn-cached + [{:keys [node]}] + (let [[sym _opts binding-vec & body] (rest (:children node))] + {:node + (hooks/list-node + (list + (hooks/token-node 'def) + sym + (hooks/list-node + (list* + (hooks/token-node 'fn) + binding-vec + body))))})) + +(defn defonce + [{:keys [node]}] + ;; args = [sym doc-string? attr-map? init-expr] + (let [[sym & args] (rest (:children node)) + [doc-string args] (if (and (hooks/string-node? (first args)) (next args)) [(hooks/sexpr (first args)) (next args)] [nil args]) + [attr-map init-expr] (if (and (hooks/map-node? (first args)) (next args)) [(hooks/sexpr (first args)) (fnext args)] [nil (first args)]) + + attr-map (if doc-string (assoc attr-map :doc doc-string) attr-map) + sym+meta (if attr-map (with-meta sym attr-map) sym) + rewritten + (hooks/list-node + [(hooks/token-node 'clojure.core/defonce) + sym+meta + init-expr])] + + {:node rewritten})) diff --git a/.clj-kondo/taoensso/encore/config.edn b/.clj-kondo/taoensso/encore/config.edn deleted file mode 100644 index 7b0ff3c2..00000000 --- a/.clj-kondo/taoensso/encore/config.edn +++ /dev/null @@ -1 +0,0 @@ -{:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}} diff --git a/.clj-kondo/taoensso/encore/taoensso/encore.clj b/.clj-kondo/taoensso/encore/taoensso/encore.clj deleted file mode 100644 index 7f6d30ac..00000000 --- a/.clj-kondo/taoensso/encore/taoensso/encore.clj +++ /dev/null @@ -1,16 +0,0 @@ -(ns taoensso.encore - (:require - [clj-kondo.hooks-api :as hooks])) - -(defn defalias [{:keys [node]}] - (let [[sym-raw src-raw] (rest (:children node)) - src (if src-raw src-raw sym-raw) - sym (if src-raw - sym-raw - (symbol (name (hooks/sexpr src))))] - {:node (with-meta - (hooks/list-node - [(hooks/token-node 'def) - (hooks/token-node (hooks/sexpr sym)) - (hooks/token-node (hooks/sexpr src))]) - (meta src))})) diff --git a/.github/workflows/shared-setup/action.yml b/.github/workflows/shared-setup/action.yml index 28c77347..d7673b18 100644 --- a/.github/workflows/shared-setup/action.yml +++ b/.github/workflows/shared-setup/action.yml @@ -30,7 +30,7 @@ runs: java-version: ${{ inputs.jdk }} - name: Install Clojure Tools - uses: DeLaGuardo/setup-clojure@12.5 + uses: DeLaGuardo/setup-clojure@13.2 with: cli: 'latest' bb: 'latest' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c36421c0..3aaf79f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: - name: Setup uses: ./.github/workflows/shared-setup with: - jdk: '11' + jdk: '24' - name: Lint run: bb lint @@ -30,7 +30,7 @@ jobs: matrix: os: [{name: 'windows', shell: 'pwsh'}, {name: 'ubuntu', shell: 'bash'}] clojure-version: ["1.8", "1.9", "1.10", "1.11", "1.12"] - jdk: ['8', '11', '17', '21'] + jdk: ['8', '11', '17', '21', '24'] name: ${{ matrix.os.name }} clj-${{ matrix.clojure-version }} jdk${{ matrix.jdk }} diff --git a/bb.edn b/bb.edn index 7c5be060..d8b4e659 100644 --- a/bb.edn +++ b/bb.edn @@ -45,7 +45,7 @@ :task publish/-main} neil ;; let's not rely on a random version of neil {:doc "Pinned version of babashka/neil (used in scripting)" - :extra-deps {io.github.babashka/neil {:git/tag "v0.3.67" :git/sha "054ca51"}} + :extra-deps {io.github.babashka/neil {:git/tag "v0.3.68" :git/sha "78ffab1"}} :task babashka.neil/-main} ;; hidden tasks, no need for folks to be trying these ci invoked tasks -ci-clojars-deploy diff --git a/deps.edn b/deps.edn index 01362de3..b428c2d2 100644 --- a/deps.edn +++ b/deps.edn @@ -12,19 +12,19 @@ :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:mvn/version "0.10.5"} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.8"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} - :extra-deps {babashka/fs {:mvn/version "0.5.22"} + :extra-deps {babashka/fs {:mvn/version "0.5.24"} ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 - ch.qos.logback/logback-classic {:mvn/version "1.3.14" + ch.qos.logback/logback-classic {:mvn/version "1.3.15" :exclusions [org.slf4j/slf4j-api]} - org.slf4j/jcl-over-slf4j {:mvn/version "2.0.16"} - org.slf4j/jul-to-slf4j {:mvn/version "2.0.16"} - org.slf4j/log4j-over-slf4j {:mvn/version "2.0.16"}} + org.slf4j/jcl-over-slf4j {:mvn/version "2.0.17"} + org.slf4j/jul-to-slf4j {:mvn/version "2.0.17"} + org.slf4j/log4j-over-slf4j {:mvn/version "2.0.17"}} :exec-fn clj-http.lite.test-util.http-server/run} :test {:extra-paths ["test"] @@ -32,12 +32,12 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2024.08.29"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.02.20"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} - :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.9.1221"} - org.clojure/clojure {:mvn/version "1.11.3"} - org.slf4j/slf4j-simple {:mvn/version "2.0.16"} ;; to rid ourselves of logger warnings + :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.11.1276"} + org.clojure/clojure {:mvn/version "1.12.0"} + org.slf4j/slf4j-simple {:mvn/version "2.0.17"} ;; to rid ourselves of logger warnings } :main-opts ["-m" "antq.core" "--exclude=ch.qos.logback/logback-classic@1.4.x" ;; requires min jdk 11, we are jdk8 compatible diff --git a/script/publish.clj b/script/publish.clj index 51786b4e..1965e9b2 100644 --- a/script/publish.clj +++ b/script/publish.clj @@ -141,9 +141,9 @@ ;; followed by any attributes "$1" ;; followed by datestamp (local time is fine) - (str " - " (yyyy-mm-dd-now-utc)) + " - " (yyyy-mm-dd-now-utc) ;; followed by an AsciiDoc anchor for easy referencing - (str " [[v" version "]]") + " [[v" version "]]" ;; followed by section content "$2" ;; followed by link to commit log From dae3d781b0d63749672072a03225e4bfa316a250 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Tue, 8 Apr 2025 16:41:53 +0000 Subject: [PATCH 141/143] dev: bump clj-kondo (#82) --- deps.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps.edn b/deps.edn index b428c2d2..4094a5a8 100644 --- a/deps.edn +++ b/deps.edn @@ -32,7 +32,7 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.02.20"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.04.07"}} :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} :main-opts ["-m" "clj-kondo.main"]} :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.11.1276"} From 120d2ec49998b5e662a7884ed6ae62721494e1b5 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Mon, 2 Jun 2025 19:21:53 +0000 Subject: [PATCH 142/143] dev & test: bump deps (#83) --- deps.edn | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/deps.edn b/deps.edn index 4094a5a8..d4eefe42 100644 --- a/deps.edn +++ b/deps.edn @@ -8,17 +8,17 @@ :1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}} :1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}} :1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.3"}}} - :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.3"}}} - :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.0"}}} + :1.11 {:override-deps {org.clojure/clojure {:mvn/version "1.11.4"}}} + :1.12 {:override-deps {org.clojure/clojure {:mvn/version "1.12.1"}}} :build {:extra-paths ["build"] - :deps {io.github.clojure/tools.build {:mvn/version "0.10.8"} + :deps {io.github.clojure/tools.build {:mvn/version "0.10.9"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :http-server ;; used for to support integration tests {:extra-paths ["test" "test-resources"] - :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} - :extra-deps {babashka/fs {:mvn/version "0.5.24"} + :override-deps {org.clojure/clojure {:mvn/version "1.12.1"}} + :extra-deps {babashka/fs {:mvn/version "0.5.25"} ring/ring-jetty-adapter {:mvn/version "1.10.0"} ;; stick with version that works on jdk8 ch.qos.logback/logback-classic {:mvn/version "1.3.15" :exclusions [org.slf4j/slf4j-api]} @@ -33,10 +33,10 @@ :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.04.07"}} - :override-deps {org.clojure/clojure {:mvn/version "1.11.3"}} + :override-deps {org.clojure/clojure {:mvn/version "1.12.1"}} :main-opts ["-m" "clj-kondo.main"]} :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.11.1276"} - org.clojure/clojure {:mvn/version "1.12.0"} + org.clojure/clojure {:mvn/version "1.12.1"} org.slf4j/slf4j-simple {:mvn/version "2.0.17"} ;; to rid ourselves of logger warnings } :main-opts ["-m" "antq.core" @@ -44,4 +44,6 @@ "--exclude=ch.qos.logback/logback-classic@1.5.x" ;; requires min jdk 11, we are jdk8 compatible "--exclude=ring/ring-jetty-adapter@1.11.x" ;; requires jdk 11, we are jdk8 compatible "--exclude=ring/ring-jetty-adapter@1.12.x" ;; requires jdk 11, we are jdk8 compatible + "--exclude=ring/ring-jetty-adapter@1.13.x" ;; requires jdk 11, we are jdk8 compatible + "--exclude=ring/ring-jetty-adapter@1.14.x" ;; requires jdk 11, we are jdk8 compatible ]}}} From 27c82755af18dad5bb5636b36e91c65963546113 Mon Sep 17 00:00:00 2001 From: Lee Read Date: Fri, 6 Jun 2025 14:15:48 +0000 Subject: [PATCH 143/143] dev & ci: bump deps (#84) New setup-clojure fixes windows issues on new releases of clojure. New clj-kondo! --- .github/workflows/shared-setup/action.yml | 2 +- deps.edn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shared-setup/action.yml b/.github/workflows/shared-setup/action.yml index d7673b18..f45355bb 100644 --- a/.github/workflows/shared-setup/action.yml +++ b/.github/workflows/shared-setup/action.yml @@ -30,7 +30,7 @@ runs: java-version: ${{ inputs.jdk }} - name: Install Clojure Tools - uses: DeLaGuardo/setup-clojure@13.2 + uses: DeLaGuardo/setup-clojure@13.4 with: cli: 'latest' bb: 'latest' diff --git a/deps.edn b/deps.edn index d4eefe42..79483879 100644 --- a/deps.edn +++ b/deps.edn @@ -32,7 +32,7 @@ {:git/tag "v0.5.1" :git/sha "dfb30dd"}} :main-opts ["-m" "cognitect.test-runner"]} ;; for consistent linting we use a specific version of clj-kondo through the jvm - :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.04.07"}} + :clj-kondo {:extra-deps {clj-kondo/clj-kondo {:mvn/version "2025.06.05"}} :override-deps {org.clojure/clojure {:mvn/version "1.12.1"}} :main-opts ["-m" "clj-kondo.main"]} :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "2.11.1276"}