0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-03 10:31:38 -05:00

Merge pull request #118 from uxbox/devenv-improvements

Docker/Devenv Improvements
This commit is contained in:
Andrey Antukh 2019-09-21 15:11:13 +02:00 committed by GitHub
commit c9d7de4022
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 228 additions and 471 deletions

View file

@ -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 ##
```

View file

@ -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;

View file

@ -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]))

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)]

View file

@ -2,6 +2,7 @@ FROM ubuntu:bionic
LABEL maintainer="Andrey Antukh <niwi@niwi.nz>"
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"]

View file

@ -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

View file

@ -1,5 +1,3 @@
#!/usr/bin/env zsh
set -ex
sudo pg_ctlcluster 11 main start
exec "$@"

8
docker/devenv/files/init.sh Executable file
View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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)))))

View file

@ -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

100
manage.sh
View file

@ -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
;;