From e45ad2197a82d458003f72fde9cb6d7932006015 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 20 Sep 2019 17:31:03 +0200 Subject: [PATCH 1/6] :sparkles: Improve the current docker development environment. --- backend/scripts/run-tests-in-docker.sh | 6 +- docker/devenv/Dockerfile | 7 +- docker/devenv/docker-compose.yaml | 55 ++++++++++++++ docker/devenv/files/entrypoint.sh | 2 - docker/devenv/files/init.sh | 8 ++ docker/devenv/files/start.sh | 2 +- docker/devenv/files/zshrc | 2 +- manage.sh | 100 +++++++++++++------------ 8 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 docker/devenv/docker-compose.yaml create mode 100755 docker/devenv/files/init.sh diff --git a/backend/scripts/run-tests-in-docker.sh b/backend/scripts/run-tests-in-docker.sh index d2ac2226c..81a3bc5a7 100755 --- a/backend/scripts/run-tests-in-docker.sh +++ b/backend/scripts/run-tests-in-docker.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -x - -clj -Adev -m uxbox.tests.main +set -xe +sudo pg_ctlcluster 11 main start; +clojure -Adev -m uxbox.tests.main; diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index 40d3dc9f1..968287408 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:bionic LABEL maintainer="Andrey Antukh " ARG EXTERNAL_UID=1000 +ARG DEBIAN_FRONTEND=noninteractive ENV NODE_VERSION=v10.16.3 \ CLOJURE_VERSION=1.10.1.469 \ @@ -37,7 +38,6 @@ RUN set -ex; \ echo "deb http://repos.azulsystems.com/ubuntu stable main" >> /etc/apt/sources.list.d/zulu.list; \ echo "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main" >> /etc/apt/sources.list.d/postgresql.list; -ARG DEBIAN_FRONTEND=noninteractive RUN set -ex; \ apt-get -qq update; \ @@ -86,9 +86,10 @@ RUN set -ex; \ COPY files/bashrc /home/uxbox/.bashrc COPY files/zshrc /home/uxbox/.zshrc COPY files/vimrc /home/uxbox/.vimrc -COPY files/start.sh /home/uxbox/start-tmux.sh +COPY files/start.sh /home/uxbox/start.sh COPY files/tmux.conf /home/uxbox/.tmux.conf COPY files/entrypoint.sh /home/uxbox/ +COPY files/init.sh /home/uxbox/ ENTRYPOINT ["zsh", "/home/uxbox/entrypoint.sh"] -CMD ["/home/uxbox/start-tmux.sh"] +CMD ["/home/uxbox/start.sh"] diff --git a/docker/devenv/docker-compose.yaml b/docker/devenv/docker-compose.yaml new file mode 100644 index 000000000..a373a7489 --- /dev/null +++ b/docker/devenv/docker-compose.yaml @@ -0,0 +1,55 @@ +version: '3' + +networks: + default: + driver: bridge + ipam: + config: + - subnet: 172.177.09.0/24 + +volumes: + postgres_data: + user_data: + +services: + uxbox: + privileged: true + build: + context: ./ + hostname: 'uxbox-devenv' + container_name: 'uxbox-devenv' + command: "/home/uxbox/init.sh" + stop_signal: SIGINT + depends_on: + - postgres + volumes: + - "user_data:/home/uxbox/local" + - "${PWD}:/home/uxbox/uxbox" + - "${HOME}/.m2:/home/uxbox/.m2" + - "${HOME}/.gitconfig:/home/uxbox/.gitconfig" + + ports: + - 3449:3449 + - 6060:6060 + + environment: + - UXBOX_HTTP_SERVER_DEBUG=false + - UXBOX_DATABASE_URI="jdbc:postgresql://postgres/uxbox" + - UXBOX_DATABASE_USERNAME="uxbox" + - UXBOX_DATABASE_PASSWORD="uxbox_postgres_password" + + postgres: + image: postgres:11 + hostname: 'uxbox-devenv-postgres' + container_name: 'uxbox-devenv-postgres' + restart: always + stop_signal: SIGINT + ports: + - 5432:5432 + environment: + - POSTGRES_INITDB_ARGS="--data-checksums" + - POSTGRES_DB=uxbox + - POSTGRES_USER=uxbox + - POSTGRES_PASSWORD=uxbox_postgres_password + volumes: + - postgres_data:/var/lib/postgresql/data diff --git a/docker/devenv/files/entrypoint.sh b/docker/devenv/files/entrypoint.sh index 39082837c..e2f98cf75 100644 --- a/docker/devenv/files/entrypoint.sh +++ b/docker/devenv/files/entrypoint.sh @@ -1,5 +1,3 @@ #!/usr/bin/env zsh set -ex -sudo pg_ctlcluster 11 main start - exec "$@" diff --git a/docker/devenv/files/init.sh b/docker/devenv/files/init.sh new file mode 100755 index 000000000..104e18f5b --- /dev/null +++ b/docker/devenv/files/init.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env zsh +set -e; + +echo "[init.sh] Setting up local permissions." +sudo chown -R uxbox /home/uxbox/local + +echo "[init.sh] Ready!" +tail -f /dev/null diff --git a/docker/devenv/files/start.sh b/docker/devenv/files/start.sh index d5bb65752..4a8976d52 100755 --- a/docker/devenv/files/start.sh +++ b/docker/devenv/files/start.sh @@ -10,7 +10,7 @@ tmux send-keys -t uxbox 'clojure -Adev tools.clj figwheel' enter tmux new-window -t uxbox:2 -n 'backend' tmux select-window -t uxbox:2 tmux send-keys -t uxbox 'cd uxbox/backend' enter C-l -tmux send-keys -t uxbox 'clojure -Adev -m uxbox.fixtures' enter C-l +# tmux send-keys -t uxbox 'clojure -Adev -m uxbox.fixtures' enter C-l tmux send-keys -t uxbox 'clojure -Adev:repl' enter tmux rename-window -t uxbox:0 'gulp' diff --git a/docker/devenv/files/zshrc b/docker/devenv/files/zshrc index 0f4b86593..e5c654b1c 100644 --- a/docker/devenv/files/zshrc +++ b/docker/devenv/files/zshrc @@ -47,7 +47,7 @@ setopt NOBEEP setopt INC_APPEND_HISTORY export HISTSIZE=100000 export SAVEHIST=100000 -export HISTFILE=~/.zhistory +export HISTFILE=~/local/.zhistory setopt hist_ignore_all_dups setopt hist_ignore_space diff --git a/manage.sh b/manage.sh index 152f3e9be..1b154bc5f 100755 --- a/manage.sh +++ b/manage.sh @@ -2,55 +2,42 @@ set -e REV=`git log -n 1 --pretty=format:%h -- docker/` -IMGNAME="uxbox-devenv" - -function kill-devenv-container { - echo "Cleaning development container $IMGNAME:$REV..." - docker ps -a -f name=$IMGNAME -q | xargs --no-run-if-empty docker kill -} +IMGNAME="devenv_uxbox" function remove-devenv-images { echo "Clean old development image $IMGNAME..." docker images $IMGNAME -q | awk '{print $3}' | xargs --no-run-if-empty docker rmi } -function build-devenv-image { +function build-devenv { + echo "Building development image $IMGNAME:latest with UID $EXTERNAL_UID..." + local EXTERNAL_UID=${1:-$(id -u)} - echo "Building development image $IMGNAME:$REV with UID $EXTERNAL_UID..." - docker build --rm=true \ - -t $IMGNAME:$REV \ - -t $IMGNAME:latest \ - --build-arg EXTERNAL_UID=$EXTERNAL_UID \ - --label="io.uxbox.devenv" \ - docker/devenv + docker-compose -f docker/devenv/docker-compose.yaml \ + build --build-arg EXTERNAL_UID=$EXTERNAL_UID --force-rm; } -function build-devenv-image-if-not-exists { - if [[ ! $(docker images $IMGNAME:$REV -q) ]]; then - build-devenv-image $@ +function build-devenv-if-not-exists { + if [[ ! $(docker images $IMGNAME:latest -q) ]]; then + build-devenv $@ fi } +function start-devenv { + build-devenv-if-not-exists $@; + docker-compose -f docker/devenv/docker-compose.yaml up -d; +} + +function stop-devenv { + docker-compose -f docker/devenv/docker-compose.yaml stop -t 2; +} + function run-devenv { - kill-devenv-container; - build-devenv-image-if-not-exists $@; + if [[ ! $(docker ps -f "name=uxbox-devenv" -q) ]]; then + start-devenv + fi - mkdir -p $HOME/.m2 - rm -rf ./frontend/node_modules - mkdir -p \ - ./frontend/resources/public/css \ - ./frontend/resources/public/view/css - - CONTAINER=$IMGNAME:latest - - echo "Running development image $CONTAINER..." - docker run --rm -ti \ - -v `pwd`:/home/uxbox/uxbox \ - -v $HOME/.m2:/home/uxbox/.m2 \ - -v $HOME/.gitconfig:/home/uxbox/.gitconfig \ - -p 3449:3449 -p 6060:6060 -p 9090:9090 \ - --name "uxbox-devenv" \ - $CONTAINER + docker exec -ti uxbox-devenv /home/uxbox/start.sh; } function run-all-tests { @@ -61,7 +48,7 @@ function run-all-tests { } function run-frontend-tests { - build-devenv-image-if-not-exists $@; + build-devenv-if-not-exists $@; CONTAINER=$IMGNAME:latest @@ -74,7 +61,7 @@ function run-frontend-tests { } function run-backend-tests { - build-devenv-image-if-not-exists $@; + build-devenv-if-not-exists $@; CONTAINER=$IMGNAME:latest @@ -86,7 +73,7 @@ function run-backend-tests { } function build-frontend-local { - build-devenv-image-if-not-exists $@; + build-devenv-if-not-exists $@; mkdir -p $HOME/.m2 rm -rf ./frontend/node_modules @@ -158,6 +145,8 @@ function build-backend-image { } function build-images { + build-devenv-if-not-exists $@; + echo "Building frontend image ..." build-frontend-image || exit 1; echo "Building frontend dbg image ..." @@ -197,11 +186,17 @@ function usage { echo "USAGE: $0 OPTION" echo "Options:" echo "- clean Stop and clean up docker containers" - echo "- build-devenv-image Build docker container for development with tmux. Can specify external user id in parameter" - echo "- run-devenv Run (and build if necessary) development container (frontend at localhost:3449, backend at localhost:6060). Can specify external user id in parameter" - echo "- run-all-tests Execute unit tests for both backend and frontend. Can specify external user id in parameter" - echo "- run-frontend-tests Execute unit tests for frontend only. Can specify external user id in parameter" - echo "- run-backend-tests Execute unit tests for backend only. Can specify external user id in parameter" + echo "" + echo "- build-devenv Build docker development oriented image; (can specify external user id in parameter)" + echo "- start-devenv Start the development oriented docker-compose service." + echo "- stop-devenv Stops the development oriented docker-compose service." + echo "- run-devenv Attaches to the running devenv container and starts development environment" + echo " based on tmux (frontend at localhost:3449, backend at localhost:6060)." + echo "" + echo "- run-all-tests Execute unit tests for both backend and frontend." + echo "- run-frontend-tests Execute unit tests for frontend only." + echo "- run-backend-tests Execute unit tests for backend only." + echo "" echo "- build-images Build a 'release ready' docker images for both backend and frontend" echo "- build-frontend-image Build a 'release ready' docker image for frontend (debug version)" echo "- build-frontend-dbg-image Build a debug docker image for frontend" @@ -213,15 +208,26 @@ function usage { case $1 in clean) - kill-devenv-container remove-devenv-images ;; - build-devenv-image) - build-devenv-image ${@:2} + + ## devenv related commands + + build-devenv) + build-devenv ${@:2} + ;; + start-devenv) + start-devenv ${@:2} ;; run-devenv) run-devenv ${@:2} ;; + stop-devenv) + stop-devenv ${@:2} + ;; + + ## testin related commands + run-all-tests) run-all-tests ${@:2} ;; @@ -232,6 +238,8 @@ case $1 in run-backend-tests ${@:2} ;; + # production related comands + build-images) build-images ;; From 4425b1a54cf9e05e05aae2f5d02b089808a9dad6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 21 Sep 2019 11:01:15 +0000 Subject: [PATCH 2/6] :bug: Fix many bugs introduced with body parsing refactor. --- backend/src/uxbox/api/pages.clj | 2 +- backend/src/uxbox/api/projects.clj | 2 +- backend/src/uxbox/http/middleware.clj | 28 ++++++++++++++++++++------- backend/src/uxbox/util/transit.clj | 19 ++++++++++++++---- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/backend/src/uxbox/api/pages.clj b/backend/src/uxbox/api/pages.clj index 4001c8817..315a19426 100644 --- a/backend/src/uxbox/api/pages.clj +++ b/backend/src/uxbox/api/pages.clj @@ -126,7 +126,7 @@ (s/keys :req-un [::id])) (s/def ::retrieve-page-history|query - (s/keys :req-un [::max + (s/keys :opt-un [::max ::since ::pinned])) diff --git a/backend/src/uxbox/api/projects.clj b/backend/src/uxbox/api/projects.clj index 5167a80d9..9b587cf2c 100644 --- a/backend/src/uxbox/api/projects.clj +++ b/backend/src/uxbox/api/projects.clj @@ -20,7 +20,7 @@ (s/def ::id ::us/uuid) (s/def ::name string?) -(s/def ::version (s/and int? pos?)) +(s/def ::version int?) ;; --- List Projects diff --git a/backend/src/uxbox/http/middleware.clj b/backend/src/uxbox/http/middleware.clj index 3d7c4db9e..8bdd59302 100644 --- a/backend/src/uxbox/http/middleware.clj +++ b/backend/src/uxbox/http/middleware.clj @@ -7,6 +7,7 @@ (ns uxbox.http.middleware (:require [clojure.spec.alpha :as s] + [clojure.java.io :as io] [cuerdas.core :as str] [promesa.core :as p] [reitit.ring :as rr] @@ -208,7 +209,7 @@ (def format-response-middleware (letfn [(process-response [{:keys [body] :as rsp}] - (if body + (if (coll? body) (let [body (t/encode body {:type :json-verbose})] (-> rsp (assoc :body body) @@ -226,11 +227,24 @@ (letfn [(get-content-type [request] (or (:content-type request) (get (:headers request) "content-type"))) + + (slurp-bytes [body] + (with-open [input (io/input-stream body) + output (java.io.ByteArrayOutputStream. (.available input))] + (io/copy input output) + (.toByteArray output))) + + (parse-body [body] + (let [^bytes body (slurp-bytes body)] + (when (pos? (alength body)) + (t/decode body)))) + (process-request [request] (let [ctype (get-content-type request)] (if (= "application/transit+json" ctype) (try - (assoc request :body-params (t/decode (:body request))) + (let [body (parse-body (:body request))] + (assoc request :body-params body)) (catch Exception e (ex/raise :type :parse :message "Unable to parse transit from request body." @@ -243,11 +257,11 @@ ([request] (handler (process-request request))) ([request respond raise] - (try - (let [request (process-request request)] - (handler request respond raise)) - (catch Exception e - (raise e))))))})) + (let [^HttpInput body (:body request)] + (try + (handler (process-request request) respond raise) + (catch Exception e + (raise e)))))))})) (def middleware [cors-middleware diff --git a/backend/src/uxbox/util/transit.clj b/backend/src/uxbox/util/transit.clj index 15c25c0b2..4254a1caf 100644 --- a/backend/src/uxbox/util/transit.clj +++ b/backend/src/uxbox/util/transit.clj @@ -49,17 +49,28 @@ ;; --- High-Level Api +;; TODO: check performance of different options + (defn decode ([data] (decode data nil)) ([data opts] - (with-open [input (io/input-stream data)] - (read! (reader input opts))))) + (cond + (string? data) + (decode (.getBytes data "UTF-8") opts) + + (bytes? data) + (with-open [input (ByteArrayInputStream. data)] + (read! (reader input opts))) + + :else + (with-open [input (io/input-stream data)] + (read! (reader input opts)))))) (defn encode - ([data] + (^bytes [data] (encode data nil)) - ([data opts] + (^bytes [data opts] (with-open [out (ByteArrayOutputStream.)] (let [w (writer out opts)] (write! w data) From 9ceb6c26445923135cedff322217ec30ae5ac32f Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 21 Sep 2019 11:01:32 +0000 Subject: [PATCH 3/6] :fire: Remove some commented code. --- backend/test/uxbox/tests/test_projects.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/test/uxbox/tests/test_projects.clj b/backend/test/uxbox/tests/test_projects.clj index 2229bfeac..d0c3d8b4a 100644 --- a/backend/test/uxbox/tests/test_projects.clj +++ b/backend/test/uxbox/tests/test_projects.clj @@ -43,7 +43,7 @@ (let [uri (str th/+base-url+ "/api/projects/" (:id proj)) params {:body (assoc proj :name "proj2")} [status data] (th/http-put user uri params)] - (prn "RESPONSE:" status data) + ;; (prn "RESPONSE:" status data) (t/is (= 200 status)) (t/is (= (:user data) (:id user))) (t/is (= (:name data) "proj2"))))))) @@ -55,6 +55,7 @@ (th/with-server {:handler @http/app} (let [uri (str th/+base-url+ "/api/projects/" (:id proj)) [status data] (th/http-delete user uri)] + ;; (prn "RESPONSE:" status data) (t/is (= 204 status)) (let [sqlv ["SELECT * FROM projects WHERE \"user\"=? AND deleted_at is null" (:id user)] From 0be3a181e6d7035bbc908dfe9a6436bba75fb55d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 21 Sep 2019 11:40:57 +0000 Subject: [PATCH 4/6] :fire: Remove group based tests (no longer relevant). --- frontend/scripts/build-and-run-tests.sh | 4 +- .../tests/test_main_data_shapes_impl.cljs | 344 ------------------ 2 files changed, 1 insertion(+), 347 deletions(-) diff --git a/frontend/scripts/build-and-run-tests.sh b/frontend/scripts/build-and-run-tests.sh index 4a388a63c..258e5b50c 100755 --- a/frontend/scripts/build-and-run-tests.sh +++ b/frontend/scripts/build-and-run-tests.sh @@ -4,7 +4,5 @@ source ~/.bashrc set -ex; npm ci - -clojure -Adev tools.clj build-tests - +clojure -Adev tools.clj build:tests node ./target/tests/main diff --git a/frontend/test/uxbox/tests/test_main_data_shapes_impl.cljs b/frontend/test/uxbox/tests/test_main_data_shapes_impl.cljs index e5d58caeb..a9385679a 100644 --- a/frontend/test/uxbox/tests/test_main_data_shapes_impl.cljs +++ b/frontend/test/uxbox/tests/test_main_data_shapes_impl.cljs @@ -179,109 +179,6 @@ (t/is (= result expected)) (t/is (vector? (get-in result [:pages 1 :shapes]))))) -;; drop shape: move shape outside of group - -(t/deftest drop-shape-test5 - (let [initial {:workspace {:selected #{1}} - :pages {1 {:id 1 :shapes [1 3]}} - :shapes {1 {:id 1 :page 1 :type :group :items [2]} - 2 {:id 2 :page 1 :group 1} - 3 {:id 3 :page 1}}} - expected {:workspace {:selected #{}} - :pages {1 {:id 1, :shapes [3 2]}}, - :shapes {2 {:id 2, :page 1}, - 3 {:id 3, :page 1}}} - result (impl/drop-shape initial 2 3 :after)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)) - (t/is (vector? (get-in result [:pages 1 :shapes]))))) - -;; drop shape: move group inside group - -(t/deftest drop-shape-test6 - (let [initial {:pages {1 {:id 1 :shapes [1 2]}} - :shapes {1 {:id 1 :page 1 :type :group :items [3]} - 2 {:id 2 :page 1 :type :group :items [4]} - 3 {:id 3 :page 1 :group 1} - 4 {:id 4 :page 1 :group 2}}} - expected {:pages {1 {:id 1, :shapes [1]}}, - :shapes {1 {:id 1, :page 1, :type :group, :items [3 2]}, - 2 {:id 2, :page 1, :type :group, :items [4], :group 1}, - 3 {:id 3, :page 1, :group 1}, - 4 {:id 4, :page 1, :group 2}}} - result (impl/drop-shape initial 2 3 :after)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)) - (t/is (vector? (get-in result [:pages 1 :shapes]))))) - -;; drop shape: move group outside group - -(t/deftest drop-shape-test7 - (let [initial {:workspace {:selected #{}} - :pages {1 {:id 1 :shapes [1 3]}} - :shapes {1 {:id 1 :page 1 :type :group :items [2]} - 2 {:id 2 :page 1 :group 1 :type :group :items [4]} - 3 {:id 3 :page 1} - 4 {:id 4 :page 1 :group 2}}} - - expected {:workspace {:selected #{}}, - :pages {1 {:id 1, :shapes [2 3]}}, - :shapes {2 {:id 2, :page 1, :type :group, :items [4]}, - 3 {:id 3, :page 1}, - 4 {:id 4, :page 1, :group 2}}} - result (impl/drop-shape initial 2 1 :after)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)) - (t/is (vector? (get-in result [:pages 1 :shapes]))))) - -;; drop shape: move shape to neested group - -(t/deftest drop-shape-test8 - (let [initial {:pages {1 {:id 1 :shapes [1 5 6]}} - :shapes {1 {:id 1 :page 1 :type :group :items [2]} - 2 {:id 2 :page 1 :type :group :group 1 :items [3 4]} - 3 {:id 3 :page 1 :group 2} - 4 {:id 4 :page 1 :group 2} - 5 {:id 5 :page 1} - 6 {:id 6 :page 1}}} - - expected {:pages {1 {:id 1, :shapes [1 5]}}, - :shapes {1 {:id 1, :page 1, :type :group, :items [2]}, - 2 {:id 2, :page 1, :type :group, :group 1, :items [3 4 6]}, - 3 {:id 3, :page 1, :group 2}, - 4 {:id 4, :page 1, :group 2}, - 5 {:id 5, :page 1}, - 6 {:id 6, :page 1, :group 2}}} - result (impl/drop-shape initial 6 4 :after)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - -;; drop shape: move shape to neested group - -(t/deftest drop-shape-test9 - (let [initial {:pages {1 {:id 1 :shapes [1]}} - :shapes {1 {:id 1 :page 1 :type :group :items [2 5 6]} - 2 {:id 2 :page 1 :type :group :group 1 :items [3 4]} - 3 {:id 3 :page 1 :group 2} - 4 {:id 4 :page 1 :group 2} - 5 {:id 5 :page 1 :group 1} - 6 {:id 6 :page 1 :group 1}}} - expected {:pages {1 {:id 1, :shapes [1]}}, - :shapes {1 {:id 1, :page 1, :type :group, :items [2 5]}, - 2 {:id 2, :page 1, :type :group, :group 1, :items [3 4 6]}, - 3 {:id 3, :page 1, :group 2}, - 4 {:id 4, :page 1, :group 2}, - 5 {:id 5, :page 1, :group 1}, - 6 {:id 6, :page 1, :group 2}}} - result (impl/drop-shape initial 6 4 :after)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Delete Shape ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -306,244 +203,3 @@ ;; (pprint expected) ;; (pprint result) (t/is (= result expected)))) - -;; delete shape: delete from group - -(t/deftest delete-shape-test2 - (let [initial {:workspace {:selected #{}} - :pages {1 {:id 1 :shapes [1 3 4]}} - :shapes {1 {:id 1 :page 1 - :type :group - :items [2]} - 2 {:id 2 :page 1 :group 1} - 3 {:id 3 :page 1} - 4 {:id 4 :page 1}}} - shape (get-in initial [:shapes 2]) - expected {:workspace {:selected #{}} - :pages {1 {:id 1 :shapes [3 4]}} - :shapes {3 {:id 3 :page 1} - 4 {:id 4 :page 1}}} - result (impl/dissoc-shape initial shape)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Group Shapes -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; group a shape - -(t/deftest group-shapes-1 - (let [initial {:pages {1 {:id 1 :shapes [1 2 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1} - 3 {:id 3 :page 1}}} - - expected {:pages {1 {:id 1 :shapes [1 4 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 4} - 3 {:id 3 :page 1} - 4 {:type :group :name "Group-1" :items [2] :id 4 :page 1}} - :workspace {:selected #{4}}}] - (with-redefs [uxbox.util.uuid/random (constantly 4)] - (let [result (impl/group-shapes initial [2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))))) - -;; group two shapes - -(t/deftest group-shapes-2 - (let [initial {:pages {1 {:id 1 :shapes [1 2 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1} - 3 {:id 3 :page 1}}} - - - expected {:pages {1 {:id 1 :shapes [1 4]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 4} - 3 {:id 3 :page 1 :group 4} - 4 {:type :group :name "Group-1" :items [2 3] :id 4 :page 1}} - :workspace {:selected #{4}}}] - (with-redefs [uxbox.util.uuid/random (constantly 4)] - (let [result (impl/group-shapes initial [2 3] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))))) - -;; group group - -(t/deftest group-shapes-3 - (let [initial {:pages {1 {:id 1 :shapes [1 2 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1} - 3 {:id 3 :page 1 :type :group}}} - expected {:pages {1 {:id 1 :shapes [1 4]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 4} - 3 {:id 3 :page 1 :type :group :group 4} - 4 {:type :group :name "Group-1" :items [2 3] :id 4 :page 1}} - :workspace {:selected #{4}}}] - (with-redefs [uxbox.util.uuid/random (constantly 4)] - (let [result (impl/group-shapes initial [2 3] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))))) - -;; group shapes inside a group - -(t/deftest group-shapes-4 - (let [initial {:pages {1 {:id 1 :shapes [1 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group}}} - - expected {:pages {1 {:id 1 :shapes [1 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 4} - 3 {:id 3 :page 1 :type :group :items [4]} - 4 {:type :group - :name "Group-1" - :items [2] - :id 4 - :page 1 - :group 3}} - :workspace {:selected #{4}}}] - (with-redefs [uxbox.util.uuid/random (constantly 4)] - (let [result (impl/group-shapes initial [2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))))) - -;; group shapes in multiple groups - -(t/deftest group-shapes-5 - (let [initial {:pages {1 {:id 1 :shapes [3 4]}} - :shapes {1 {:id 1 :page 1 :group 4} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group :items [2]} - 4 {:id 4 :page 1 :type :group :imtes [3]}}} - - expected (-> initial - (assoc-in [:workspace :selected] #{5}) - (assoc-in [:pages 1 :shapes] [5]) - (assoc-in [:shapes 1 :group] 5) - (assoc-in [:shapes 2 :group] 5) - (assoc-in [:shapes 5] {:type :group :name "Group-1" - :items [1 2] :id 5 :page 1}) - (update-in [:shapes] dissoc 3) - (update-in [:shapes] dissoc 4))] - (with-redefs [uxbox.util.uuid/random (constantly 5)] - (let [result (impl/group-shapes initial [1 2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Degroups -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; degroup a single group - -(t/deftest degroup-shapes-1-0 - (let [initial {:pages {1 {:id 1 :shapes [3]}} - :shapes {1 {:id 1 :page 1 :group 3} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group :items [1 2]}}} - expected {:workspace {:selected #{1 2}} - :pages {1 {:id 1 :shapes [1 2]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1}}}] - (let [result (impl/degroup-shapes initial [3] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected))))) - -;; degroup single shape from group - -(t/deftest degroup-shapes-1-1 - (let [initial {:pages {1 {:id 1 :shapes [3]}} - :shapes {1 {:id 1 :page 1 :group 3} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group :items [1 2]}}} - expected {:workspace {:selected #{1}} - :pages {1 {:id 1 :shapes [1 3]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group :items [2]}}} - result (impl/degroup-shapes initial [1] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - - -;; degroup all shapes from group - -(t/deftest degroup-shapes-1-2 - (let [initial {:pages {1 {:id 1 :shapes [3]}} - :shapes {1 {:id 1 :page 1 :group 3} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :type :group :items [1 2]}}} - expected {:workspace {:selected #{1 2}} - :pages {1 {:id 1 :shapes [1 2]}} - :shapes {1 {:id 1 :page 1} - 2 {:id 2 :page 1}}} - result (impl/degroup-shapes initial [1 2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - - -;; degroup all shapes from neested group - -(t/deftest degroup-shapes-1-3 - (let [initial {:pages {1 {:id 1 :shapes [4]}} - :shapes {1 {:id 1 :page 1 :group 3} - 2 {:id 2 :page 1 :group 3} - 3 {:id 3 :page 1 :group 4 :type :group :items [1 2]} - 4 {:id 4 :page 1 :type :group :items [3]}}} - expected {:workspace {:selected #{1 2}} - :pages {1 {:id 1 :shapes [4]}} - :shapes {1 {:id 1 :page 1 :group 4} - 2 {:id 2 :page 1 :group 4} - 4 {:id 4 :page 1 :type :group :items [1 2]}}} - result (impl/degroup-shapes initial [1 2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected)))) - -;; degroup group inside a group - -(t/deftest degroup-shapes-2 - (let [initial {:pages {1 {:id 1 :shapes [1]}} - :shapes {1 {:id 1 :page 1 :type :group :items [2]} - 2 {:id 2 :page 1 :type :group :items [3] :group 1} - 3 {:id 3 :page 1 :group 2}}} - - expected {:pages {1 {:id 1 :shapes [1]}} - :shapes {1 {:id 1 :page 1 :type :group :items [3]} - 3 {:id 3 :page 1 :group 1}} - :workspace {:selected #{3}}}] - (let [result (impl/degroup-shapes initial [2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected))))) - -;; degroup multiple groups not nested - -(t/deftest degroup-shapes-3 - (let [initial {:pages {1 {:id 1 :shapes [1 2]}} - :shapes {1 {:id 1 :page 1 :type :group :items [3]} - 2 {:id 2 :page 1 :type :group :items [4]} - 3 {:id 3 :page 1 :group 1} - 4 {:id 4 :page 1 :group 2}}} - - expected {:pages {1 {:id 1 :shapes [3 4]}} - :shapes {3 {:id 3 :page 1} 4 {:id 4 :page 1}} - :workspace {:selected #{4 3}}}] - (let [result (impl/degroup-shapes initial [1 2] 1)] - ;; (pprint expected) - ;; (pprint result) - (t/is (= result expected))))) From d8edf07367a5247fc374820b582e8ac71f4cc41a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 21 Sep 2019 11:41:18 +0000 Subject: [PATCH 5/6] :sparkles: Add watch:tests command to tools.clj script. --- frontend/tools.clj | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/frontend/tools.clj b/frontend/tools.clj index 9e5a3e84b..a204050e6 100644 --- a/frontend/tools.clj +++ b/frontend/tools.clj @@ -130,12 +130,9 @@ (task ["dbg-dist:main"]) (task ["dbg-dist:worker"])) - - - ;; --- Tests Tasks -(defmethod task "build-tests" +(defmethod task "build:tests" [& args] (api/build (api/inputs "src" "test") (assoc default-build-options @@ -147,6 +144,30 @@ :output-dir "target/tests/main" :optimizations :none))) +(defmethod task "watch:tests" + [args] + (println "Start watch loop...") + (letfn [(run-tests [] + (let [{:keys [out err]} (shell/sh "node" "target/tests/main.js")] + (println out err))) + (start-watch [] + (try + (api/watch (api/inputs "src" "test") + (assoc default-build-options + :main 'uxbox.tests.main + :watch-fn run-tests + :target :nodejs + :source-map true + :output-to "target/tests/main.js" + :output-dir "target/tests/main" + :optimizations :none)) + (catch Exception e + (println "ERROR:" e) + (Thread/sleep 2000) + start-watch)))] + (trampoline start-watch))) + + ;; --- Figwheel Config & Tasks (def figwheel-builds From 74224694c3e6a1e0d73b2d12988236a3377a58df Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 21 Sep 2019 12:02:32 +0000 Subject: [PATCH 6/6] :books: Update README file. --- README.md | 86 +++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 90ea12c6d..3ac2d1aa2 100644 --- a/README.md +++ b/README.md @@ -30,25 +30,27 @@ editable in many other vector tools and easy to use on the web. ### Introduction ### -The development environment consists in a docker container that mounts -your local copy of the uxbox souce code directory tree and executes a -tmux inside the container in order to facilitate execute multiple -processes inside. +The main development environment consists in a docker compose +configuration that starts the external services and the development +container (called **devenv**). + +We use tmux script in order to multiplex the signle terminal and run +both the backend and frontend in the same container. ### System requirements ### -You should have `docker` installed in your system in order to set up -properly the uxbox development enviroment. +You should have `docker` and `docker-compose` installed in your system +in order to set up properly the uxbox development enviroment. In debian like linux distributions you can install it executing: ```bash -sudo apt-get install docker +sudo apt-get install docker docker-compose ``` -### Start the docker container ### +### Start the devenv ### **Requires a minimum knowledge of tmux usage in order to use that development environment.** @@ -61,10 +63,9 @@ For start it, staying in this repository, execute: This will do the following: -- Build the image if it is not done before. -- Download all repositories if them are not downloaded previously. -- Start a container with predefined tmux layout. -- Start all needed processes such as gulp and figwheel. +- Build the images if it is not done before. +- Starts all the containers in the background. +- Attaches to the **devenv** container and executes the tmux session. ### First steps with tmux ### @@ -82,36 +83,37 @@ current window. #### UI #### -The UI related tasks starts automatically so you do not need do anything. The -**window 0** and **window 1** are used for the UI related environment. +The UI related tasks starts automatically so you do not need do +anything. The **window 0** and **window 1** are used for the UI +related environment. #### Backend #### -The backend related environment is located in the **window 2**, and you can go -directly to it using `ctrl+b 2` shortcut. +The backend related environment is located in the **window 2**, and +you can go directly to it using `ctrl+b 2` shortcut. -By default this tasks are performed: - -- Start postgresql. -- Load initial fixtures into the database. - -The repl should be started automatically, if not, you can execute: - -```bash -clojure -Adev:repl -``` +By default the clojure repl will be executed, waiting you to run +commands or start the http server. Then use `(start)` to start all the environment, `(stop)` for stoping it and `(reset)` for restart with code reloading. If some exception is -raised when code is reloaded, just use `(refresh)` in order to finish +raised when code is reloaded, just use `(repl/refresh)` in order to finish correctly the code swaping and later use `(reset)` again. +If this is your first run, you maybe want to load fixtures first. Then +you can done this in two ways: + +- In the same repl, require the `uxbox.fixtures` namespace and execute + `(uxbox.fixtures/-main [])`. +- Stop the repl with `Ctrl+c` and then execute `clojure -Adev -m + uxbox.fixtures`; then start the repl again with `clojure -Adev:repl`. + ## Production (Docker) Docker is also used to build release images for backend and -frontend. Use the helper script `manage.sh` to build the images. You +frontend. Use the helper script `manage.sh` to build the images. You can run locally UXBOX through a docker-compose or by manually running the containers. @@ -129,35 +131,16 @@ uploads, etc). The docker daemon will store that data within the docker directory `/var/lib/docker/volumes/...`. That means your data is saved even if the container crashes, is stopped or deleted. -To make your data persistent to upgrading and get access for backups -is using named docker volume or mount a host folder. To achieve this -you need one volume for your database container. +The default production docker-compose already handles it for you, +but if you. So check the `docker/docker-compose.yml` file. -Database: -- `/var/lib/postgresql/data` PostgreSQL Data -```console -$ docker run -d \ - -v db:/var/lib/postgresql/data \ - postgresql -``` - -You also need to persist the UXBOX backend public resources (media and -assets) to not lose images uploaded and allow the frontend to expose -assets. - -- `/srv/uxbox/resources/public` UXBOX backend public resources - -```console -$ docker run -d \ - -v db:/srv/uxbox/resources/public \ - monogramm/docker-uxbox-backend -``` ### Auto configuration via environment variables The following environment variables are also honored for configuring your UXBOX instance: + #### Frontend **Only available at build time!** @@ -205,6 +188,7 @@ Available at runtime: variables or the backend might try to interpret the values as symbols and have weird issues. + ## Collections import You can easily import icons and images as global stores with the @@ -243,6 +227,7 @@ clojure -Adev -m uxbox.cli.collimp ../media/config.edn Take a look at the `sample_media` directory for a sample configuration. + ## Contributing ## **Open to you!** @@ -253,6 +238,7 @@ and improve UXBOX. All your awesome ideas and code are welcome! Please refer to the [Contributing Guide](./CONTRIBUTING.md) + ## License ## ```