diff --git a/.dockerignore b/.dockerignore new file mode 100755 index 0000000..c51f4a8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +node_modules +.idea + +.git + +docker/ +!docker/concordia-contracts/migrate.sh +!docker/concordia-contracts/test-contracts.sh +!docker/concordia-app/test-app.sh +!docker/concordia-app/nginx.conf +!docker/concordia-app/create-environment.sh +!docker/concordia-app/run.sh +!docker/ganache/start-blockchain.sh + +packages/*/node_modules +packages/*/dist +packages/*/coverage +packages/*/*.env* +# TO-NEVER-DO: exclude the build folder of the contracts package, it's needed for building the application image. +packages/concordia-app/build + +Jenkinsfile + +README.md +packages/*/README.md \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 6313b56..02ac587 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ +# Set the default behavior, in case people don't have core.autocrlf set. * text=auto eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.ico binary + +# Solidity +*.sol linguist-language=Solidity diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index dd40e6f..7bbaae4 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,38 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. - # Node /node_modules -package-lock.json +packages/*/node_modules +packages/concordia-contracts/build -# Testing -/coverage +# IDE +.DS_Store +.idea -# Production +# Build Directories /build /src/build +/packages/concordia-app/build +/packages/concordia-contracts/build + +# Logs +/log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Docker volumes +docker/volumes +docker/ganache/volumes +docker/concordia-contracts-provider/volumes +docker/concordia-pinner/volumes +docker/reports # Misc -.DS_Store .env.local .env.development.local .env.test.local .env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* +# Lerna +*.lerna_backup -# Jetbrains -.idea +yarn-clean.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6e4a383 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 ECEntrics + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 06c9e71..f80fded 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,18 @@ -# Apella +# Concordia +> A distributed forum using Blockchain, supporting direct democratic voting -*Note: This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).* +## Setup + +You can find detailed instructions on how to get started with each service in the respective package directories. The +overall setup pipeline **for development** is this though: + +- start rendezvous server and ganache +- migrate contracts +- start application + +## Using Docker images + +This project provides docker images for a number of services required to set up Concordia, as well as for Concordia +itself. + +Check out the README.md in the `./docker` directory diff --git a/contracts/Forum.sol b/contracts/Forum.sol deleted file mode 100644 index 3732646..0000000 --- a/contracts/Forum.sol +++ /dev/null @@ -1,88 +0,0 @@ -pragma solidity ^0.4.17; - -contract Forum { - - //----------------------------------------USER---------------------------------------- - struct User { - string userName; // TODO: set an upper bound instead of arbitrary string - // TODO: orbitDBAddress; - uint[] topicIDs; // IDs of the topics the user created - uint[] postIDs; // IDs of the posts the user created - } - - mapping (address => User) users; - mapping (string => address) userAddresses; - - function signUp(string userName) public returns (bool) { // Also allows user to update his name - TODO: his previous name will appear as taken - require(!isUserNameTaken(userName)); - users[msg.sender] = User(userName, new uint[](0), new uint[](0)); - userAddresses[userName] = msg.sender; - return true; - } - - function login() public view returns (string) { - require (hasUserSignedUp(msg.sender)); - return users[msg.sender].userName; - } - - function getUsername(address userAddress) public view returns (string) { - return users[userAddress].userName; - } - - function getUserAddress(string userName) public view returns (address) { - return userAddresses[userName]; - } - - function hasUserSignedUp(address userAddress) public view returns (bool) { - if (bytes(getUsername(userAddress)).length!=0) - return true; - return false; - } - - function isUserNameTaken(string userName) public view returns (bool) { - if (getUserAddress(userName)!=0) - return true; - return false; - } - - //----------------------------------------TOPIC---------------------------------------- - struct Topic { - uint topicID; - address author; - uint timestamp; - uint[] postIDs; - } - - struct Post { - uint postID; - address author; - uint timestamp; - } - - uint numTopics; // Total number of topics - uint numPosts; // Total number of posts - - mapping (uint => Topic) topics; - mapping (uint => Post) posts; - - function createTopic() public returns (uint topicID) { - require(hasUserSignedUp(msg.sender)); // Only registered users can create topics - topicID = numTopics++; - topics[topicID] = Topic(topicID, msg.sender, block.timestamp, new uint[](0)); - users[msg.sender].topicIDs.push(topicID); - } - - function createPost(uint topicID) public returns (uint postID) { - require(hasUserSignedUp(msg.sender)); // Only registered users can create posts - require(topicID Makefile targets + +Concordia uses blockchain and other distributed technologies. There are a number of ways to set up a running instance of +this application. + +This chapter will guide you through simple setups for testing and production that depend on local blockchain (ganache) +instances which do not require real ETH to work or have any other charges. + +#### Testing the contracts + +Build the ganache image and spin up a blockchain for testing: + +```shell +make build-ganache run-ganache-test +``` + +Build the testing stage of the contracts image: + +```shell +make build-contracts-tests +``` + +Run the tests: + +```shell +make run-contracts-tests +``` + +The results should be printed in the terminal, but are also available in the directory `./reports/contracts`. + +#### Testing the application + +Build the testing stage of the application image: + +```shell +make build-app-tests +``` + +Run the test: + +```shell +make run-app-tests +``` + +The results should be printed in the terminal, but are also available in the directory `./reports/app`. + +#### Production + +Just run the target: + +```shell +make run +``` + +And you' re done! Head to [localhost:7777](localhost:7777) and voilĂ , a working Concordia instance appears! The +blockchain is exposed in the address `localhost:8545`. + +**Tip**: the accounts (private keys) generated by Ganache are available in the file `./volumes/ganache_keys/keys.json`. + +Note that the `make run` command might take several minutes to execute (depending on your system). What happens under +the hood is that: + +- the ganache image is built +- blockchain and rendezvous server containers are started +- migration stage of the contracts image is built +- the contracts are deployed to the blockchain: +- the application image is built and then deployed + +### Env Files + +Targets in the Makefile make use of env files located in the directory `./env`. Using this environment variables, you +can change various configuration options of the testing/production deploys. + +Makefile targets suffixed with `host-chain` will try to use a blockchain and rendezvous server running in the host +machine. They use the `--net=host` docker option. In order to work with these targets you need to create and use your +own env files (or modify the existing ones). The environment variables values will largely depend on how you choose to +run the services in your system (which ports you use etc.), so be sure to create them before running any `host-chain` +target. diff --git a/docker/concordia-app/Dockerfile b/docker/concordia-app/Dockerfile new file mode 100755 index 0000000..4ba629c --- /dev/null +++ b/docker/concordia-app/Dockerfile @@ -0,0 +1,97 @@ +# -------------------------------------------------- +# Stage 1 (Init application build base) +# -------------------------------------------------- +FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as base +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis " +LABEL gr.thmmy.ecentrics.concordia-image.name="app" + +WORKDIR /usr/src/concordia + +# Copy the root package.json and yarn.lock +COPY ./package.json . +COPY ./yarn.lock . + +# Copy package.json files from contracts, shared and app, then install modules +COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/package.json +COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/package.json +COPY ./packages/concordia-app/package.json ./packages/concordia-app/ + +# Install required packages +RUN apk update && apk --no-cache add g++ make python + +RUN yarn install --frozen-lockfile + +# Gets the rest of the source code +COPY ./packages/concordia-contracts ./packages/concordia-contracts +COPY ./packages/concordia-shared ./packages/concordia-shared +COPY ./packages/concordia-app ./packages/concordia-app + +# Fix timezome +ARG TZ +ENV TZ=${TZ} +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# -------------------------------------------------- +# Stage 2 (Test) +# -------------------------------------------------- +FROM base as test + +WORKDIR /opt/concordia-app + +COPY ./docker/concordia-app/test-app.sh . + +WORKDIR /usr/src/concordia/packages/concordia-app + +RUN ["chmod", "+x", "/opt/concordia-app/test-app.sh"] + +ENTRYPOINT ["/opt/concordia-app/test-app.sh"] + +# -------------------------------------------------- +# Stage 3 (Build) +# -------------------------------------------------- +FROM base as build + +WORKDIR /usr/src/concordia/packages/concordia-app + +RUN yarn build + +# -------------------------------------------------- +# Stage 4 (Staging runtime) +# -------------------------------------------------- +FROM base as staging + +WORKDIR /usr/src/concordia/packages/concordia-app + +ENTRYPOINT ["yarn", "start"] + +# -------------------------------------------------- +# Stage 4 (Production runtime) +# -------------------------------------------------- +FROM nginx:1.17-alpine@sha256:01747306a7247dbe928db991eab42e4002118bf636dd85b4ffea05dd907e5b66 as production +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis /etc/timezone \ + && apk del tzdata \ + && rm -rf /var/cache/apk/* + +COPY ./docker/concordia-app/create-environment.sh /opt/concordia/create-environment.sh +COPY ./docker/concordia-app/run.sh /opt/concordia/run.sh + +RUN ["chmod", "+x", "/opt/concordia/create-environment.sh"] +RUN ["chmod", "+x", "/opt/concordia/run.sh"] + +COPY ./docker/concordia-app/nginx.conf /etc/nginx/conf.d/default.conf + +WORKDIR "/var/www/concordia-app" + +COPY --chown=nginx:nginx --from=build /usr/src/concordia/packages/concordia-app/build . + +CMD ["/opt/concordia/run.sh"] diff --git a/docker/concordia-app/create-environment.sh b/docker/concordia-app/create-environment.sh new file mode 100755 index 0000000..c089455 --- /dev/null +++ b/docker/concordia-app/create-environment.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +echo "window.runtimeEnv = { \ +REACT_APP_CONCORDIA_HOST: \"${REACT_APP_CONCORDIA_HOST}\", \ +REACT_APP_CONCORDIA_PORT: \"${REACT_APP_CONCORDIA_PORT}\", \ +REACT_APP_WEB3_HOST: \"${REACT_APP_WEB3_HOST}\", \ +REACT_APP_WEB3_PORT: \"${REACT_APP_WEB3_PORT}\", \ +REACT_APP_RENDEZVOUS_HOST: \"${REACT_APP_RENDEZVOUS_HOST}\", \ +REACT_APP_RENDEZVOUS_PORT: \"${REACT_APP_RENDEZVOUS_PORT}\", \ +REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER: \"${REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER}\", \ +REACT_APP_CONTRACTS_PROVIDER_HOST: \"${REACT_APP_CONTRACTS_PROVIDER_HOST}\", \ +REACT_APP_CONTRACTS_PROVIDER_PORT: \"${REACT_APP_CONTRACTS_PROVIDER_PORT}\", \ +REACT_APP_CONTRACTS_VERSION_HASH: \"${REACT_APP_CONTRACTS_VERSION_HASH}\", \ +}" >/var/www/concordia-app/environment.js diff --git a/docker/concordia-app/nginx.conf b/docker/concordia-app/nginx.conf new file mode 100644 index 0000000..cb598c0 --- /dev/null +++ b/docker/concordia-app/nginx.conf @@ -0,0 +1,22 @@ +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/host.access.log main; + + location / { + root /var/www/concordia-app; + index index.html index.htm; + try_files "$uri" "$uri/" /index.html; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/docker/concordia-app/run.sh b/docker/concordia-app/run.sh new file mode 100755 index 0000000..e0c073e --- /dev/null +++ b/docker/concordia-app/run.sh @@ -0,0 +1,3 @@ +sh /opt/concordia/create-environment.sh + +exec "$(which nginx)" -g "daemon off;" diff --git a/docker/concordia-app/test-app.sh b/docker/concordia-app/test-app.sh new file mode 100644 index 0000000..32a6a76 --- /dev/null +++ b/docker/concordia-app/test-app.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +yarn lint -f html -o /mnt/concordia/test-reports/concordia-app-eslint.html --no-color + +if [ $? -eq 0 ]; then + echo "TESTS RAN SUCCESSFULLY!" + exit 0 +else + echo "SOME TESTS FAILED!" + exit 1 +fi diff --git a/docker/concordia-contracts-provider/Dockerfile b/docker/concordia-contracts-provider/Dockerfile new file mode 100644 index 0000000..fc8ef71 --- /dev/null +++ b/docker/concordia-contracts-provider/Dockerfile @@ -0,0 +1,36 @@ +# -------------------------------------------------- +# Stage 1 (Runtime) +# -------------------------------------------------- +FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as runtime +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis " +LABEL gr.thmmy.ecentrics.concordia-image.name="contracts-provider" + +# Fix timezome (needed for timestamps on report files) +ARG TZ + +RUN apk add -U tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone \ + && apk del tzdata \ + && rm -rf /var/cache/apk/* + +WORKDIR /usr/src/concordia + +# Copy the root package.json and yarn.lock +COPY ./package.json . +COPY ./yarn.lock . + +# Copy package.json files from shared and contracts provider, then install modules +COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/ +COPY ./packages/concordia-contracts-provider/package.json ./packages/concordia-contracts-provider/ + +RUN yarn install --frozen-lockfile --network-timeout 100000 + +# Gets the rest of the source code +COPY ./packages/concordia-shared ./packages/concordia-shared +COPY ./packages/concordia-contracts-provider ./packages/concordia-contracts-provider + +WORKDIR /usr/src/concordia/packages/concordia-contracts-provider + +ENTRYPOINT ["yarn", "start"] \ No newline at end of file diff --git a/docker/concordia-contracts/Dockerfile b/docker/concordia-contracts/Dockerfile new file mode 100755 index 0000000..3c1e1bb --- /dev/null +++ b/docker/concordia-contracts/Dockerfile @@ -0,0 +1,70 @@ +# -------------------------------------------------- +# Stage 1 (Init contracts build base) +# -------------------------------------------------- +FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as base +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis " +LABEL gr.thmmy.ecentrics.concordia-image.name="contracts" + +# Fix timezome (needed for timestamps on report files) +ARG TZ + +RUN apk add -U tzdata \ + && cp /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone \ + && apk del tzdata \ + && rm -rf /var/cache/apk/* + +WORKDIR /usr/src/concordia + +# Copy the root package.json and yarn.lock +COPY ./package.json . +COPY ./yarn.lock . + +# Copy package.json files from shared and contracts, then install modules +COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/ +COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/ + +RUN yarn install --frozen-lockfile --network-timeout 100000 + +# Gets the rest of the source code +COPY ./packages/concordia-shared ./packages/concordia-shared +COPY ./packages/concordia-contracts ./packages/concordia-contracts + +# -------------------------------------------------- +# Stage 2 (Compile) +# -------------------------------------------------- +FROM base as compile + +WORKDIR /usr/src/concordia/packages/concordia-contracts +RUN yarn compile + +# -------------------------------------------------- +# Stage 3 (Test) +# -------------------------------------------------- +FROM compile as test + +WORKDIR /opt/concordia-contracts + +COPY ./docker/concordia-contracts/test-contracts.sh . + +WORKDIR /usr/src/concordia/packages/concordia-contracts + +RUN ["chmod", "+x", "/opt/concordia-contracts/test-contracts.sh"] + +ENTRYPOINT ["/opt/concordia-contracts/test-contracts.sh"] + +# -------------------------------------------------- +# Stage 4 (Runtime) +# -------------------------------------------------- +FROM compile as runtime +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis " +LABEL gr.thmmy.ecentrics.concordia-image.name="contracts" + +WORKDIR /opt/concordia-contracts + +COPY ./docker/concordia-contracts/migrate.sh . +RUN ["chmod", "+x", "/opt/concordia-contracts/migrate.sh"] + +ENTRYPOINT ["/opt/concordia-contracts/migrate.sh"] diff --git a/docker/concordia-contracts/migrate.sh b/docker/concordia-contracts/migrate.sh new file mode 100755 index 0000000..f44afa0 --- /dev/null +++ b/docker/concordia-contracts/migrate.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +export CHAIN_HOST="$DEPLOY_CHAIN_HOST" +export CHAIN_PORT="$DEPLOY_CHAIN_PORT" + +cd /usr/src/concordia/packages/concordia-contracts && + yarn _migrate --network "${MIGRATE_NETWORK}" --reset && + yarn _upload ${CONTRACTS_VERSION_HASH} ${CONTRACTS_VERSION_TAG} diff --git a/docker/concordia-contracts/test-contracts.sh b/docker/concordia-contracts/test-contracts.sh new file mode 100644 index 0000000..f441048 --- /dev/null +++ b/docker/concordia-contracts/test-contracts.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +export CHAIN_HOST="$TEST_CHAIN_HOST" +export CHAIN_PORT="$TEST_CHAIN_PORT" + +yarn _eslint -f html -o /mnt/concordia/test-reports/concordia-contracts-eslint.html --no-color +ESLINT_EXIT_STATUS=$? + +yarn _solhint >/mnt/concordia/test-reports/concordia-contracts-solhint.report +SOLHINT_EXIT_STATUS=$? + +yarn test --network env >/mnt/concordia/test-reports/concordia-contracts-truffle-tests.report +grep -qE failing /mnt/concordia/test-reports/concordia-contracts-truffle-tests.report +TRUFFLE_TEST_FAILING=$? + +if [ $ESLINT_EXIT_STATUS -eq 0 ] && [ "$SOLHINT_EXIT_STATUS" -eq 0 ] && [ "$TRUFFLE_TEST_FAILING" -eq 1 ]; then + echo "TESTS RAN SUCCESSFULLY!" + exit 0 +else + echo "SOME TESTS FAILED!" + exit 1 +fi diff --git a/docker/concordia-pinner/Dockerfile b/docker/concordia-pinner/Dockerfile new file mode 100644 index 0000000..3c9389c --- /dev/null +++ b/docker/concordia-pinner/Dockerfile @@ -0,0 +1,34 @@ +# -------------------------------------------------- +# Stage 1 (Runtime) +# -------------------------------------------------- +FROM node:14-buster@sha256:32362e2ea89c62d77c86c8f26ad936dbbdc170cd6c06c4d7ff7a809012bb0c32 as runtime +LABEL maintainers.1="Apostolos Fanakis " +LABEL maintainers.2="Panagiotis Nikolaidis " +LABEL gr.thmmy.ecentrics.concordia-image.name="pinner" + +# Fix timezome (needed for timestamps on report files) +ARG TZ +ENV TZ=${TZ} +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +WORKDIR /usr/src/concordia + +# Copy the root package.json and yarn.lock +COPY ./package.json . +COPY ./yarn.lock . + +# Copy package.json files from contracts, shared and pinner, then install modules +COPY ./packages/concordia-pinner/package.json ./packages/concordia-pinner/ +COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/ +COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/ + +RUN yarn install --frozen-lockfile --network-timeout 100000 + +# Gets the rest of the source code +COPY ./packages/concordia-shared ./packages/concordia-shared +COPY ./packages/concordia-contracts ./packages/concordia-contracts +COPY ./packages/concordia-pinner ./packages/concordia-pinner + +WORKDIR /usr/src/concordia/packages/concordia-pinner + +ENTRYPOINT ["yarn", "start"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100755 index 0000000..d6eaf70 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + ganache: + build: + context: ../ + dockerfile: ./docker/ganache/Dockerfile + image: ecentrics/concordia-ganache + container_name: concordia-ganache + env_file: + - env/ganache.env + expose: + - 8545 + ports: + - 8545:8545 + user: root + volumes: + - ./ganache/volumes/ganache_keys:/mnt/concordia/ganache_keys + networks: + concordia_network: + restart: always + + rendezvous: + image: libp2p/js-libp2p-webrtc-star:version-0.21.1 + container_name: concordia-rendezvous + networks: + concordia_network: + ports: + - 9090:9090 + restart: always + +networks: + concordia_network: diff --git a/docker/env/concordia.env b/docker/env/concordia.env new file mode 100755 index 0000000..a02c1de --- /dev/null +++ b/docker/env/concordia.env @@ -0,0 +1,5 @@ +# Variables needed in runtime (in browser) +REACT_APP_RENDEZVOUS_HOST=/ip4/127.0.0.1 +REACT_APP_RENDEZVOUS_PORT=9090 +REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER=true +REACT_APP_CONTRACTS_VERSION_HASH=docker diff --git a/docker/env/contracts-provider.env b/docker/env/contracts-provider.env new file mode 100644 index 0000000..63b52ed --- /dev/null +++ b/docker/env/contracts-provider.env @@ -0,0 +1,3 @@ +UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/ +LOGS_PATH=/mnt/concordia/logs/ +#CORS_ALLOWED_ORIGINS="http://127.0.0.1:7000;http://localhost:7000;http://127.0.0.1:7777;http://localhost:7777;http://127.0.0.1:4444;127.0.0.1:4444" diff --git a/docker/env/contracts-test.env b/docker/env/contracts-test.env new file mode 100755 index 0000000..8489346 --- /dev/null +++ b/docker/env/contracts-test.env @@ -0,0 +1,4 @@ +# Variables needed in runtime +MIGRATE_NETWORK=env +WEB3_HOST=concordia-ganache-test +WEB3_PORT=8546 diff --git a/docker/env/contracts.env b/docker/env/contracts.env new file mode 100755 index 0000000..d3bea08 --- /dev/null +++ b/docker/env/contracts.env @@ -0,0 +1,8 @@ +# Variables needed in runtime +MIGRATE_NETWORK=env +WEB3_HOST=concordia-ganache +WEB3_PORT=8545 + +CONTRACTS_PROVIDER_HOST=http://concordia-contracts-provider +CONTRACTS_PROVIDER_PORT=8400 +CONTRACTS_VERSION_HASH=docker diff --git a/docker/env/ganache.env b/docker/env/ganache.env new file mode 100755 index 0000000..0187b06 --- /dev/null +++ b/docker/env/ganache.env @@ -0,0 +1,5 @@ +ACCOUNTS_NUMBER=10 +ACCOUNTS_ETHER=100 +HOST=0.0.0.0 +PORT=8545 +NETWORK_ID=5778 diff --git a/docker/env/ganache.test.env b/docker/env/ganache.test.env new file mode 100755 index 0000000..b81f7a7 --- /dev/null +++ b/docker/env/ganache.test.env @@ -0,0 +1,6 @@ +ACCOUNTS_NUMBER=5 +ACCOUNTS_ETHER=100 +MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect" +HOST=0.0.0.0 +PORT=8546 +NETWORK_ID=5778 diff --git a/docker/env/pinner.env b/docker/env/pinner.env new file mode 100644 index 0000000..0c7f948 --- /dev/null +++ b/docker/env/pinner.env @@ -0,0 +1,17 @@ +USE_EXTERNAL_CONTRACTS_PROVIDER=true +IPFS_DIRECTORY=/mnt/concordia/ipfs +ORBIT_DIRECTORY=/mnt/concordia/orbitdb +LOGS_PATH=/mnt/concordia/logs/ + +CONTRACTS_PROVIDER_HOST=http://concordia-contracts-provider +CONTRACTS_PROVIDER_PORT=8400 +CONTRACTS_VERSION_HASH=docker + +PINNER_API_HOST=127.0.0.1 +PINNER_API_PORT=4444 + +RENDEZVOUS_HOST=/docker/concordia-rendezvous +RENDEZVOUS_PORT=9090 + +WEB3_HOST=concordia-ganache +WEB3_PORT=8545 diff --git a/docker/ganache/Dockerfile b/docker/ganache/Dockerfile new file mode 100644 index 0000000..a97baef --- /dev/null +++ b/docker/ganache/Dockerfile @@ -0,0 +1,10 @@ +FROM trufflesuite/ganache-cli:v6.12.2@sha256:c062707f17f355872d703cde3de6a12fc45a027ed42857c72514171a5f466ab7 + +RUN mkdir -p /mnt/concordia/ganache_db /mnt/concordia/ganache_keys + +WORKDIR /opt/concordia-ganache + +COPY ./docker/ganache/start-blockchain.sh . +RUN ["chmod", "+x", "/opt/concordia-ganache/start-blockchain.sh"] + +ENTRYPOINT ["/opt/concordia-ganache/start-blockchain.sh"] diff --git a/docker/ganache/start-blockchain.sh b/docker/ganache/start-blockchain.sh new file mode 100644 index 0000000..0a373b8 --- /dev/null +++ b/docker/ganache/start-blockchain.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +N_ACCOUNTS="${ACCOUNTS_NUMBER:-10}" +ETHER="${ACCOUNTS_ETHER:-10}" +HOST="${HOST:-"0.0.0.0"}" +PORT="${PORT:-8545}" +ID="${NETWORK_ID:-5778}" + +if [ -z "${MNEMONIC}" ]; then + echo "Starting Ganache with non deterministic address generation" + node /app/ganache-core.docker.cli.js \ + --accounts "$N_ACCOUNTS" \ + --defaultBalanceEther "$ETHER" \ + --host "$HOST" \ + --port "$PORT" \ + --networkId "$ID" \ + --account_keys_path "/mnt/concordia/ganache_keys/keys.json" \ + --db "/mnt/concordia/ganache_db/" \ + --allowUnlimitedContractSize \ + --noVMErrorsOnRPCResponse \ + --verbose +else + echo "Starting Ganache with deterministic address generation" + node /app/ganache-core.docker.cli.js \ + --accounts "$N_ACCOUNTS" \ + --defaultBalanceEther "$ETHER" \ + --mnemonic "$MNEMONIC" \ + --host "$HOST" \ + --port "$PORT" \ + --networkId "$ID" \ + --account_keys_path "/mnt/concordia/ganache_keys/keys.json" \ + --db "/mnt/concordia/ganache_db/" \ + --allowUnlimitedContractSize \ + --noVMErrorsOnRPCResponse \ + --deterministic \ + --verbose +fi diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile new file mode 100755 index 0000000..d5f1e02 --- /dev/null +++ b/jenkins/Jenkinsfile @@ -0,0 +1,781 @@ +#!groovy + +def cleanSlateEnabled +def sanitizedBranchName + +// Package change state +def appPackageChanged +def contractsPackageChanged +def contractsProviderPackageChanged +def pinnerPackageChanged +def sharedPackageChanged + +// Package versions +def appPackageVersion +def contractsPackageVersion +def contractsProviderPackageVersion +def pinnerPackageVersion +def sharedPackageVersion + +// Docker images +def appImage +def contractsImage +def contractsProviderImage +def pinnerImage + +def freshGanacheStagingRunning = false +def freshGanacheProductionRunning = false + +def successResultGif = "https://media.giphy.com/media/o75ajIFH0QnQC3nCeD/giphy.gif" +def failResultGif = "https://media.giphy.com/media/ljtfkyTD3PIUZaKWRi/giphy.gif" +def abortResultGif = "https://media.giphy.com/media/IzXmRTmKd0if6/giphy.gif" + +pipeline { + agent any + + post { + failure { + updateGitlabCommitStatus name: 'build', state: 'failed' + + discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build + Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT) + Build status: ${currentBuild.currentResult} + """, image: failResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}" + } + success { + updateGitlabCommitStatus name: 'build', state: 'success' + + discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build + Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT) + Build status: ${currentBuild.currentResult} + """, image: successResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}" + } + aborted { + discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build + Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT) + Build status: ${currentBuild.currentResult} + """, image: abortResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}" + } + always { + archiveArtifacts artifacts: "reports/${BUILD_NUMBER}/**/* , build/**/*, ganache/*", fingerprint: true, allowEmptyArchive: true + sleep 2 + sh 'docker images | grep -E "ecentrics/concordia.+tests" | tr -s \' \' | cut -d \' \' -f 3 | xargs --no-run-if-empty docker rmi -f || true' + sh "docker images | tr -s \' \' | grep -E \'ecentrics/concordia.+staging-b\' | sed -r \'s/(v.*-staging-b)([0-9]*)/\\1\\2 \\2/g\' | awk \'{ if (\$3 < ($BUILD_NUMBER - 2)) print \$1\":\"\$2}\' | xargs --no-run-if-empty docker rmi -f || true" + sh "docker images | tr -s \' \' | grep -E \'ecentrics/concordia.+production-b\' | sed -r \'s/(v.*-production-b)([0-9]*)/\\1\\2 \\2/g\' | awk \'{ if (\$3 < ($BUILD_NUMBER - 2)) print \$1\":\"\$2}\' | xargs --no-run-if-empty docker rmi -f || true" + sh 'docker system prune -f' + sh 'rm -rf reports' + sh 'rm -rf build' + } + } + options { + gitLabConnection('apella') + } + triggers { + gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All') + } + environment { + DOCKER_BUILDKIT='1' + DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/810180975580938290/HYYeK8Nqwt0h8Arx3qPpF-szjgLkPDTqbVVKLkzcmqY7ourTpKJCAc6IuCXHd_cxowuK" + CONCORDIA_LOGO_URL="https://i.postimg.cc/MGvgy9Lp/app-logo-circle.png" + } + + stages { + stage ('VERSION') { + steps { + script { + cleanSlateEnabled = sh (script: "git log -1 | grep -qE 'ci: force'", returnStatus: true) + sanitizedBranchName = sh(script: 'echo $GIT_BRANCH | sed -e "s:.*/::g"', returnStdout: true).trim() + + appPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh app "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim() + contractsPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh contracts "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim() + contractsProviderPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh concordia-contracts-provider "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim() + pinnerPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh pinner "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim() + sharedPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh shared "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim() + + appPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-app/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim() + contractsPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-contracts/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim() + contractsProviderPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-contracts-provider/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim() + pinnerPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-pinner/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim() + sharedPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-shared/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim() + + echo "Package: app, Version: ${appPackageVersion}, Changed: ${appPackageChanged}" + echo "Package: contracts, Version: ${contractsPackageVersion}, Changed: ${contractsPackageChanged}" + echo "Package: contracts-provider, Version: ${contractsProviderPackageVersion}, Changed: ${contractsProviderPackageChanged}" + echo "Package: pinner, Version: ${pinnerPackageVersion}, Changed: ${pinnerPackageChanged}" + echo "Package: shared, Version: ${sharedPackageVersion}, Changed: ${sharedPackageChanged}" + } + } + } + + stage('TEST') { + parallel { + stage('TEST CONTRACTS') { + steps { + script { + def ganacheTestPort = sh(script: "bash ./jenkins/hash_build_properties.sh ${BRANCH_NAME} ${BUILD_NUMBER} | xargs bash ./jenkins/map_to_thousand.sh", returnStdout: true).trim() + + def ganacheTestImage = docker.build( + "ecentrics/concordia-ganache", + "-f docker/ganache/Dockerfile \ + ./" + ) + + docker.build( + "ecentrics/concordia-contracts-tests:${sanitizedBranchName}-v${contractsPackageVersion}-b${BUILD_NUMBER}-tests", + "-f docker/concordia-contracts/Dockerfile \ + ./ \ + --target test \ + --build-arg TZ=Europe/Athens" + ) + + sh 'docker network create --driver bridge concordia_ganache_test_network || true' + + ganacheTestImage.withRun("""-d -p 6${ganacheTestPort}:8546 \ + --env-file=./jenkins/env/ganache.test.jenkins.env \ + --name concordia-ganache-test-6${ganacheTestPort} \ + --net=concordia_ganache_test_network""") { concordiaGanacheTest -> + + try { + sh """docker run \ + --rm \ + -v ecentrics_janus_common:/mnt/concordia/test-reports/ \ + --env-file=./jenkins/env/contracts.test.jenkins.env \ + -e WEB3_HOST=concordia-ganache-test-6${ganacheTestPort} \ + -e WEB3_PORT=6${ganacheTestPort} \ + --net=concordia_ganache_test_network \ + ecentrics/concordia-contracts-tests:${sanitizedBranchName}-v${contractsPackageVersion}-b${BUILD_NUMBER}-tests""" + } catch (e) { + error('Some tests failed!') + error('Aborting the build.') + throw e + } finally { + sh 'mkdir -p ./reports/${BUILD_NUMBER}/contracts' + sh 'find /mnt/janus/common/ -name "concordia-contracts-*" -exec cp \'{}\' ./reports/${BUILD_NUMBER}/contracts/ \\;' + } + } + } + } + } + + stage('TEST APP') { + steps { + script { + docker.build( + "ecentrics/concordia-app:${sanitizedBranchName}-v${appPackageVersion}-b${BUILD_NUMBER}-tests", + "-f docker/concordia-app/Dockerfile \ + ./ \ + --target test \ + --build-arg TZ=Europe/Athens" + ) + + try { + sh """docker run \ + --rm \ + -v ecentrics_janus_common:/mnt/concordia/test-reports/ \ + ecentrics/concordia-app:${sanitizedBranchName}-v${appPackageVersion}-b${BUILD_NUMBER}-tests""" + } catch (e) { + error('Some tests failed!') + error('Aborting the build.') + throw e + } finally { + sh 'mkdir -p ./reports/${BUILD_NUMBER}/app' + sh 'find /mnt/janus/common/ -name "concordia-app-*" -exec cp \'{}\' ./reports/${BUILD_NUMBER}/app/ \\;' + } + } + } + } + } + } + + stage('BUILD FOR PRODUCTION') { + when { + branch 'master' + } + parallel { + stage('BUILD CONTRACTS') { + when { + expression { + return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + contractsImage = docker.build( + "ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}", + "-f docker/concordia-contracts/Dockerfile \ + ./ \ + -t ecentrics/concordia-contracts-migrate:latest \ + --build-arg TZ=Europe/Athens" + ) + + contractsImage.run('--rm \ + -v ecentrics_janus_common:/mnt/concordia/build \ + --entrypoint=sh', + "-c 'mkdir -p /mnt/concordia/build/contract-artifacts && cp /usr/src/concordia/packages/concordia-contracts/build/* /mnt/concordia/build/contract-artifacts'") + + sh 'mkdir -p ./build/${BUILD_NUMBER}/contracts' + sh 'cp /mnt/janus/common/contract-artifacts/* ./build/${BUILD_NUMBER}/contracts' + } + } + } + + stage('BUILD APP') { + when { + expression { + return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + appImage = docker.build( + "ecentrics/concordia-app:v${appPackageVersion}", + "-f docker/concordia-app/Dockerfile \ + ./ \ + -t ecentrics/concordia-app:latest \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + + stage('BUILD CONTRACTS PROVIDER') { + when { + expression { + return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + contractsProviderImage = docker.build( + "ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}", + "-f docker/concordia-contracts-provider/Dockerfile \ + ./ \ + -t ecentrics/concordia-contracts-provider:latest \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + + stage('BUILD PINNER') { + when { + expression { + return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + pinnerImage = docker.build( + "ecentrics/concordia-pinner:v${pinnerPackageVersion}", + "-f docker/concordia-pinner/Dockerfile \ + ./ \ + -t ecentrics/concordia-pinner:latest \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + } + } + + stage('BUILD FOR STAGING') { + when { + branch 'develop' + } + parallel { + stage('BUILD CONTRACTS') { + when { + expression { + return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + contractsImage = docker.build( + "ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}-staging-b${BUILD_NUMBER}", + "-f docker/concordia-contracts/Dockerfile \ + ./ \ + -t ecentrics/concordia-contracts-migrate:staging-latest \ + --build-arg TZ=Europe/Athens" + ) + + // Get contract artifacts + contractsImage.run('--rm \ + -v ecentrics_janus_common:/mnt/concordia/build \ + --entrypoint=sh', + "-c 'mkdir -p /mnt/concordia/build/contract-artifacts && cp /usr/src/concordia/packages/concordia-contracts/build/* /mnt/concordia/build/contract-artifacts'") + + sh 'mkdir -p ./build/${BUILD_NUMBER}/contracts' + sh 'cp /mnt/janus/common/contract-artifacts/* ./build/${BUILD_NUMBER}/contracts' + } + } + } + + stage('BUILD APP') { + when { + expression { + return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + appImage = docker.build( + "ecentrics/concordia-app:v${appPackageVersion}-staging-b${BUILD_NUMBER}", + "-f docker/concordia-app/Dockerfile \ + ./ \ + -t ecentrics/concordia-app:staging-latest \ + --target staging \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + + stage('BUILD CONTRACTS PROVIDER') { + when { + expression { + return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + contractsProviderImage = docker.build( + "ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}-staging-b${BUILD_NUMBER}", + "-f docker/concordia-contracts-provider/Dockerfile \ + ./ \ + -t ecentrics/concordia-contracts-provider:staging-latest \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + + stage('BUILD PINNER') { + when { + expression { + return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + pinnerImage = docker.build( + "ecentrics/concordia-pinner:v${pinnerPackageVersion}-staging-b${BUILD_NUMBER}", + "-f docker/concordia-pinner/Dockerfile \ + ./ \ + -t ecentrics/concordia-pinner:staging-latest \ + --build-arg TZ=Europe/Athens" + ) + } + } + } + } + } + + stage('PUBLISH') { + when { + branch 'master' + } + parallel { + stage('PUBLISH CONTRACTS') { + when { + expression { + return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') { + contractsImage.push() + contractsImage.push('latest') + } + } + } + } + + stage('PUBLISH APP') { + when { + expression { + return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') { + appImage.push() + appImage.push('latest') + } + } + } + } + + stage('PUBLISH CONTRACTS PROVIDER') { + when { + expression { + return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') { + contractsProviderImage.push() + contractsProviderImage.push('latest') + } + } + } + } + + stage('PUBLISH PINNER') { + when { + expression { + return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') { + pinnerImage.push() + pinnerImage.push('latest') + } + } + } + } + } + } + + stage('DEPLOY STAGING') { + when { + branch 'develop' + } + stages { + stage('STAGING DEPLOY PREPARATION') { + steps { + script { + sh 'docker network create --driver bridge ecentrics_concordia_staging_network || true' + + def rendezvousServerRunning = sh (script: 'docker ps -f name=concordia-rendezvous | \ + grep -qE concordia-rendezvous', returnStatus: true) + + if ("$rendezvousServerRunning" == '1' || "$cleanSlateEnabled" == '0') { + sh 'docker stop concordia-rendezvous || true \ + && docker rm concordia-rendezvous || true' + + sh 'docker run \ + -d \ + --env-file=./jenkins/env/rendezvous.jenkins.env \ + -p 9090:9090 \ + --name concordia-rendezvous \ + --net=ecentrics_concordia_staging_network \ + libp2p/js-libp2p-webrtc-star:version-0.21.1' + } else { + sh 'docker network connect ecentrics_concordia_staging_network concordia-rendezvous || true' + } + } + } + } + + stage('DEPLOY CONTRACTS PROVIDER') { + when { + expression { + def contractsProviderStagingRunning = sh (script: 'docker ps -f name=concordia-contracts-provider-staging | \ + grep -qE concordia-contracts-provider-staging', returnStatus: true) + return "${contractsProviderPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$contractsProviderStagingRunning" == '1' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh 'docker stop concordia-contracts-provider-staging || true \ + && docker rm concordia-contracts-provider-staging || true' + + sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \ + docker volume rm concordia-contracts-provider-staging || true; \ + fi' + + sh (script: """docker run \ + -d \ + -v concordia-contracts-provider-staging:/mnt/concordia \ + --env-file=./jenkins/env/contracts.provider.staging.env \ + -p 8450:8450 \ + --name concordia-contracts-provider-staging \ + --net=ecentrics_concordia_staging_network \ + ecentrics/concordia-contracts-provider:staging-latest""") + } + } + } + + stage('RECREATE GANACHE') { + when { + expression { + def ganacheStagingRunning = sh (script: 'docker ps -f name=concordia-ganache-staging | \ + grep -qE concordia-ganache-staging', returnStatus: true) + return "$cleanSlateEnabled" == '0' || "$ganacheStagingRunning" == '1'; + } + } + steps { + script { + sh 'docker stop concordia-ganache-staging || true \ + && docker rm concordia-ganache-staging || true' + + sh 'docker volume rm concordia-ganache-staging || true' + + sh (script: 'docker run \ + -d \ + -v concordia-ganache-staging:/mnt/concordia \ + -p 8555:8555 \ + --env-file=./jenkins/env/ganache.staging.jenkins.env \ + --name concordia-ganache-staging \ + --net=ecentrics_concordia_staging_network \ + ecentrics/concordia-ganache:latest') + + // Ganache image might take a while to come alive + sleep 10 + + sh 'mkdir -p ./ganache/ && docker cp concordia-ganache-staging:/mnt/concordia/ganache_keys/keys.json ./ganache/' + freshGanacheStagingRunning = true + } + } + } + + stage('DEPLOY CONTRACTS') { + when { + expression { + return "${contractsPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$freshGanacheStagingRunning" || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh """docker run \ + --rm \ + --env-file=./jenkins/env/contracts.staging.jenkins.env \ + -e CONTRACTS_VERSION_HASH=${contractsPackageVersion}-dev \ + --net=ecentrics_concordia_staging_network \ + ecentrics/concordia-contracts-migrate:staging-latest""" + } + } + } + + stage('DEPLOY PINNER') { + when { + expression { + def pinnerStagingRunning = sh (script: 'docker ps -f name=concordia-pinner-staging | \ + grep -qE concordia-pinner-staging', returnStatus: true) + return "${pinnerPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh 'docker stop concordia-pinner-staging || true \ + && docker rm concordia-pinner-staging || true' + + sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \ + docker volume rm concordia-pinner-staging || true; \ + fi' + + sh """docker run \ + -d \ + -v concordia-pinner-staging:/mnt/concordia/ \ + -p 5555:5555 \ + --env-file=./jenkins/env/pinner.staging.jenkins.env \ + --name concordia-pinner-staging \ + --net=ecentrics_concordia_staging_network \ + ecentrics/concordia-pinner:staging-latest""" + } + } + } + + stage('DEPLOY APP') { + when { + expression { + def pinnerStagingRunning = sh (script: 'docker ps -f name=concordia-app-staging | \ + grep -qE concordia-app-staging', returnStatus: true) + return "${appPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${sharedPackageChanged}" == '0'; + } + } + + steps { + script { + sh 'docker stop concordia-app-staging || true \ + && docker rm concordia-app-staging || true' + + sh """docker run \ + -itd \ + -p 7000:3000 \ + --env-file=./jenkins/env/concordia.staging.jenkins.env \ + --name concordia-app-staging \ + --net=ecentrics_concordia_staging_network \ + ecentrics/concordia-app:staging-latest""" + } + } + } + } + } + + stage('DEPLOY PRODUCTION') { + when { + branch 'master' + } + stages { + stage('PRODUCTION DEPLOY PREPARATION') { + steps { + script { + sh 'docker network create --driver bridge ecentrics_concordia_production_network || true' + + def rendezvousServerRunning = sh (script: 'docker ps -f name=concordia-rendezvous | \ + grep -qE concordia-rendezvous', returnStatus: true) + + if ("$rendezvousServerRunning" == '1' || "$cleanSlateEnabled" == '0') { + sh 'docker stop concordia-rendezvous || true \ + && docker rm concordia-rendezvous || true' + + sh 'docker run \ + -d \ + --env-file=./jenkins/env/rendezvous.jenkins.env \ + -p 9090:9090 \ + --name concordia-rendezvous \ + --net=ecentrics_concordia_production_network \ + libp2p/js-libp2p-webrtc-star:version-0.21.1' + } else { + sh 'docker network connect ecentrics_concordia_production_network concordia-rendezvous || true' + } + } + } + } + + stage('DEPLOY CONTRACTS PROVIDER') { + when { + expression { + def contractsProviderProductionRunning = sh (script: 'docker ps -f name=concordia-contracts-provider-production | \ + grep -qE concordia-contracts-provider-production', returnStatus: true) + return "${contractsProviderPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$contractsProviderProductionRunning" == '1' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh 'docker stop concordia-contracts-provider-production || true \ + && docker rm concordia-contracts-provider-production || true' + + sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \ + docker volume rm concordia-contracts-provider-production || true; \ + fi' + + sh (script: """docker run \ + -d \ + -v concordia-contracts-provider-production:/mnt/concordia \ + --env-file=./jenkins/env/contracts.provider.production.env \ + -e NODE_ENV=production \ + -p 8400:8400 \ + --name concordia-contracts-provider-production \ + --net=ecentrics_concordia_production_network \ + ecentrics/concordia-contracts-provider:latest""") + } + } + } + + stage('RECREATE GANACHE') { + when { + expression { + def ganacheProductionRunning = sh (script: 'docker ps -f name=concordia-ganache-production | \ + grep -qE concordia-ganache-production', returnStatus: true) + return "$cleanSlateEnabled" == '0' || "$ganacheProductionRunning" == '1'; + } + } + steps { + script { + sh 'docker stop concordia-ganache-production || true \ + && docker rm concordia-ganache-production || true' + + sh 'docker volume rm concordia-ganache-production || true' + + sh (script: 'docker run \ + -d \ + -v concordia-ganache-production:/mnt/concordia \ + -p 8545:8545 \ + --env-file=./jenkins/env/ganache.production.jenkins.env \ + --name concordia-ganache-production \ + --net=ecentrics_concordia_production_network \ + ecentrics/concordia-ganache:latest') + + // Ganache image might take a while to come alive + sleep 10 + + sh 'mkdir -p ./ganache/ && docker cp concordia-ganache-production:/mnt/concordia/ganache_keys/keys.json ./ganache/' + freshGanacheProductionRunning = true + } + } + } + + stage('DEPLOY CONTRACTS') { + when { + expression { + return "${contractsPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$freshGanacheProductionRunning" || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh """docker run \ + --rm \ + --env-file=./jenkins/env/contracts.production.jenkins.env \ + -e CONTRACTS_VERSION_HASH=${contractsPackageVersion} \ + --net=ecentrics_concordia_production_network \ + ecentrics/concordia-contracts-migrate:latest""" + } + } + } + + stage('DEPLOY PINNER') { + when { + expression { + def pinnerProductionRunning = sh (script: 'docker ps -f name=concordia-pinner-production | \ + grep -qE concordia-pinner-production', returnStatus: true) + return "${pinnerPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${pinnerProductionRunning}" == '1' || "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0'; + } + } + steps { + script { + sh 'docker stop concordia-pinner-production || true \ + && docker rm concordia-pinner-production || true' + + sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \ + docker volume rm concordia-pinner-production || true; \ + fi' + + sh """docker run \ + -d \ + -v concordia-pinner-production:/mnt/concordia \ + -p 4444:4444 \ + -e NODE_ENV=production \ + --env-file=./jenkins/env/pinner.production.jenkins.env \ + --name concordia-pinner-production \ + --net=ecentrics_concordia_production_network \ + ecentrics/concordia-pinner:latest""" + } + } + } + + stage('DEPLOY APP') { + when { + expression { + def appProductionRunning = sh (script: 'docker ps -f name=concordia-app-production | \ + grep -qE concordia-app-production', returnStatus: true) + return "${appPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' ||"${appProductionRunning}" == '1' || "${sharedPackageChanged}" == '0'; + } + } + + steps { + script { + sh 'docker stop concordia-app-production || true \ + && docker rm concordia-app-production || true' + + sh """docker run \ + -d \ + -p 7777:80 \ + --env-file=./jenkins/env/concordia.production.jenkins.env \ + --name concordia-app-production \ + --net=ecentrics_concordia_production_network \ + ecentrics/concordia-app:latest""" + } + } + } + } + } + } +} diff --git a/jenkins/check_package_changed.sh b/jenkins/check_package_changed.sh new file mode 100755 index 0000000..171e740 --- /dev/null +++ b/jenkins/check_package_changed.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Based on this post: +# https://engineering.brigad.co/only-deploy-services-impacted-by-changes-in-a-mono-repository-18f54b8ac109 + +APP=$1 +# Jenkins should provide these in the environment by default +GIT_COMMIT=$2 +GIT_PREVIOUS_COMMIT=$3 +ROOT_FILES_AND_FOLDERS=${4:-"package.json" "yarn.lock" ".dockerignore" "docker" "jenkins"} + +function join_by() { + local IFS="$1" + shift + echo "$*" +} + +function package_changed() { + git diff --name-only "$COMMIT_RANGE" | grep -qE "^packages/concordia-$1/" && echo true || echo false +} + +if [ "$GIT_COMMIT" == "$GIT_PREVIOUS_COMMIT" ]; then + # Probably a manual re-run, set the range to just the last commit + COMMIT_RANGE="$GIT_COMMIT" +else + COMMIT_RANGE="$GIT_PREVIOUS_COMMIT...$GIT_COMMIT" +fi + +ROOT_FILES_AND_FOLDERS_ARRAY=($ROOT_FILES_AND_FOLDERS) +ROOT_FILES_AND_FOLDERS_JOINED=$(join_by "|" ${ROOT_FILES_AND_FOLDERS_ARRAY[*]}) + +ROOT_FILES_CHANGED=$(git diff --name-only "$COMMIT_RANGE" | grep -qE "^($ROOT_FILES_AND_FOLDERS_JOINED)" && echo true || echo false) +IS_FORCE_BUILD=$(git log --oneline "$COMMIT_RANGE" | grep -qE "ci: force" && echo true || echo false) +APP_FILES_CHANGED=$(package_changed ${APP}) + +($IS_FORCE_BUILD || $ROOT_FILES_CHANGED || $APP_FILES_CHANGED) && echo 0 || echo 1 diff --git a/jenkins/env/concordia.production.jenkins.env b/jenkins/env/concordia.production.jenkins.env new file mode 100755 index 0000000..a3f3d6c --- /dev/null +++ b/jenkins/env/concordia.production.jenkins.env @@ -0,0 +1,16 @@ +VIRTUAL_HOST=concordia.ecentrics.net,www.concordia.ecentrics.net +VIRTUAL_PORT=7777 +LETSENCRYPT_HOST=concordia.ecentrics.net,www.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +# Variables needed in runtime (in browser) +REACT_APP_CONCORDIA_HOST=https://concordia.ecentrics.net +REACT_APP_CONCORDIA_PORT=443 + +REACT_APP_RENDEZVOUS_HOST=/dns4/rendezvous.ecentrics.net +REACT_APP_RENDEZVOUS_PORT=443 + +REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER=true +REACT_APP_CONTRACTS_PROVIDER_HOST=https://contracts.concordia.ecentrics.net +REACT_APP_CONTRACTS_PROVIDER_PORT=443 +REACT_APP_CONTRACTS_VERSION_HASH=stable diff --git a/jenkins/env/concordia.staging.jenkins.env b/jenkins/env/concordia.staging.jenkins.env new file mode 100755 index 0000000..6a08a97 --- /dev/null +++ b/jenkins/env/concordia.staging.jenkins.env @@ -0,0 +1,16 @@ +VIRTUAL_HOST=staging.concordia.ecentrics.net,www.staging.concordia.ecentrics.net +VIRTUAL_PORT=7000 +LETSENCRYPT_HOST=staging.concordia.ecentrics.net,www.staging.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +# Variables needed in runtime (in browser) +REACT_APP_CONCORDIA_HOST=https://staging.concordia.ecentrics.net +REACT_APP_CONCORDIA_PORT=443 + +REACT_APP_RENDEZVOUS_HOST=/dns4/rendezvous.ecentrics.net +REACT_APP_RENDEZVOUS_PORT=443 + +REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER=true +REACT_APP_CONTRACTS_PROVIDER_HOST=https://staging.contracts.concordia.ecentrics.net +REACT_APP_CONTRACTS_PROVIDER_PORT=443 +REACT_APP_CONTRACTS_VERSION_HASH=latest diff --git a/jenkins/env/contracts.production.jenkins.env b/jenkins/env/contracts.production.jenkins.env new file mode 100755 index 0000000..fe22205 --- /dev/null +++ b/jenkins/env/contracts.production.jenkins.env @@ -0,0 +1,8 @@ +# Variables needed in runtime +MIGRATE_NETWORK=env +WEB3_HOST=concordia-ganache-production +WEB3_PORT=8545 + +CONTRACTS_PROVIDER_HOST=https://contracts.concordia.ecentrics.net +CONTRACTS_PROVIDER_PORT=443 +CONTRACTS_VERSION_TAG=stable diff --git a/jenkins/env/contracts.provider.production.env b/jenkins/env/contracts.provider.production.env new file mode 100755 index 0000000..81ff6d4 --- /dev/null +++ b/jenkins/env/contracts.provider.production.env @@ -0,0 +1,9 @@ +VIRTUAL_HOST=contracts.concordia.ecentrics.net,www.contracts.concordia.ecentrics.net +VIRTUAL_PORT=8400 +LETSENCRYPT_HOST=contracts.concordia.ecentrics.net,www.contracts.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +CONTRACTS_PROVIDER_PORT=8400 +UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/ +LOGS_PATH=/mnt/concordia/logs/ +CORS_ALLOWED_ORIGINS="https://concordia.ecentrics.net:443;https://concordia.ecentrics.net;http://127.0.0.1:4444;127.0.0.1:4444" diff --git a/jenkins/env/contracts.provider.staging.env b/jenkins/env/contracts.provider.staging.env new file mode 100755 index 0000000..2210d6a --- /dev/null +++ b/jenkins/env/contracts.provider.staging.env @@ -0,0 +1,9 @@ +VIRTUAL_HOST=staging.contracts.concordia.ecentrics.net,www.staging.contracts.concordia.ecentrics.net +VIRTUAL_PORT=8450 +LETSENCRYPT_HOST=staging.contracts.concordia.ecentrics.net,www.staging.contracts.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +CONTRACTS_PROVIDER_PORT=8450 +UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/ +LOGS_PATH=/mnt/concordia/logs/ +CORS_ALLOWED_ORIGINS="https://staging.concordia.ecentrics.net:443;https://staging.concordia.ecentrics.net;http://127.0.0.1:5555;127.0.0.1:5555;https://www.staging.concordia.ecentrics.net:443;https://www.staging.concordia.ecentrics.net;http://www.127.0.0.1:5555;www.127.0.0.1:5555" diff --git a/jenkins/env/contracts.staging.jenkins.env b/jenkins/env/contracts.staging.jenkins.env new file mode 100755 index 0000000..bffdfdd --- /dev/null +++ b/jenkins/env/contracts.staging.jenkins.env @@ -0,0 +1,8 @@ +# Variables needed in runtime +MIGRATE_NETWORK=env +WEB3_HOST=concordia-ganache-staging +WEB3_PORT=8555 + +CONTRACTS_PROVIDER_HOST=https://staging.contracts.concordia.ecentrics.net +CONTRACTS_PROVIDER_PORT=443 +CONTRACTS_VERSION_TAG=latest diff --git a/jenkins/env/contracts.test.jenkins.env b/jenkins/env/contracts.test.jenkins.env new file mode 100755 index 0000000..8489346 --- /dev/null +++ b/jenkins/env/contracts.test.jenkins.env @@ -0,0 +1,4 @@ +# Variables needed in runtime +MIGRATE_NETWORK=env +WEB3_HOST=concordia-ganache-test +WEB3_PORT=8546 diff --git a/jenkins/env/ganache.production.jenkins.env b/jenkins/env/ganache.production.jenkins.env new file mode 100755 index 0000000..ff72611 --- /dev/null +++ b/jenkins/env/ganache.production.jenkins.env @@ -0,0 +1,10 @@ +VIRTUAL_HOST=ganache.ecentrics.net,www.ganache.ecentrics.net +VIRTUAL_PORT=8545 +LETSENCRYPT_HOST=ganache.ecentrics.net,www.LETSENCRYPT_HOST +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +ACCOUNTS_NUMBER=1000 +ACCOUNTS_ETHER=100000 +HOST=0.0.0.0 +PORT=8545 +NETWORK_ID=5778 diff --git a/jenkins/env/ganache.staging.jenkins.env b/jenkins/env/ganache.staging.jenkins.env new file mode 100755 index 0000000..de438cd --- /dev/null +++ b/jenkins/env/ganache.staging.jenkins.env @@ -0,0 +1,10 @@ +VIRTUAL_HOST=staging.ganache.ecentrics.net,www.staging.ganache.ecentrics.net +VIRTUAL_PORT=8555 +LETSENCRYPT_HOST=staging.ganache.ecentrics.net,www.staging.ganache.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +ACCOUNTS_NUMBER=100 +ACCOUNTS_ETHER=1000 +HOST=0.0.0.0 +PORT=8555 +NETWORK_ID=5778 diff --git a/jenkins/env/ganache.test.jenkins.env b/jenkins/env/ganache.test.jenkins.env new file mode 100755 index 0000000..479da1f --- /dev/null +++ b/jenkins/env/ganache.test.jenkins.env @@ -0,0 +1,6 @@ +ACCOUNTS_NUMBER=5 +ACCOUNTS_ETHER=1 +MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect" +HOST=0.0.0.0 +PORT=8546 +NETWORK_ID=5778 diff --git a/jenkins/env/pinner.production.jenkins.env b/jenkins/env/pinner.production.jenkins.env new file mode 100755 index 0000000..8602631 --- /dev/null +++ b/jenkins/env/pinner.production.jenkins.env @@ -0,0 +1,22 @@ +VIRTUAL_HOST=pinner.concordia.ecentrics.net,www.pinner.concordia.ecentrics.net +VIRTUAL_PORT=4444 +LETSENCRYPT_HOST=pinner.concordia.ecentrics.net,www.pinner.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +USE_EXTERNAL_CONTRACTS_PROVIDER=true +ORBIT_DIRECTORY=/mnt/concordia/orbitdb +IPFS_DIRECTORY=/mnt/concordia/ipfs +LOGS_PATH=/mnt/concordia/logs/ + +CONTRACTS_PROVIDER_HOST=https://contracts.concordia.ecentrics.net +CONTRACTS_PROVIDER_PORT=443 +CONTRACTS_VERSION_HASH=stable + +PINNER_API_HOST=https://pinner.concordia.ecentrics.net +PINNER_API_PORT=443 + +RENDEZVOUS_HOST=/dns4/rendezvous.ecentrics.net +RENDEZVOUS_PORT=443 + +WEB3_HOST=ganache.ecentrics.net +WEB3_PORT=8545 diff --git a/jenkins/env/pinner.staging.jenkins.env b/jenkins/env/pinner.staging.jenkins.env new file mode 100755 index 0000000..2b56987 --- /dev/null +++ b/jenkins/env/pinner.staging.jenkins.env @@ -0,0 +1,22 @@ +VIRTUAL_HOST=staging.pinner.concordia.ecentrics.net,www.staging.pinner.concordia.ecentrics.net +VIRTUAL_PORT=5555 +LETSENCRYPT_HOST=staging.pinner.concordia.ecentrics.net,www.staging.pinner.concordia.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + +USE_EXTERNAL_CONTRACTS_PROVIDER=true +ORBIT_DIRECTORY=/mnt/concordia/orbitdb +IPFS_DIRECTORY=/mnt/concordia/ipfs +LOGS_PATH=/mnt/concordia/logs/ + +CONTRACTS_PROVIDER_HOST=https://staging.contracts.concordia.ecentrics.net +CONTRACTS_PROVIDER_PORT=443 +CONTRACTS_VERSION_HASH=latest + +PINNER_API_HOST=https://staging.pinner.concordia.ecentrics.net +PINNER_API_PORT=443 + +RENDEZVOUS_HOST=/dns4/rendezvous.ecentrics.net +RENDEZVOUS_PORT=443 + +WEB3_HOST=staging.ganache.ecentrics.net +WEB3_PORT=8555 diff --git a/jenkins/env/rendezvous.jenkins.env b/jenkins/env/rendezvous.jenkins.env new file mode 100644 index 0000000..2604411 --- /dev/null +++ b/jenkins/env/rendezvous.jenkins.env @@ -0,0 +1,5 @@ +VIRTUAL_HOST=rendezvous.ecentrics.net,www.rendezvous.ecentrics.net +VIRTUAL_PORT=9090 +LETSENCRYPT_HOST=rendezvous.ecentrics.net,www.rendezvous.ecentrics.net +LETSENCRYPT_EMAIL=ecentricsgr@gmail.com + diff --git a/jenkins/hash_build_properties.sh b/jenkins/hash_build_properties.sh new file mode 100755 index 0000000..a30e81c --- /dev/null +++ b/jenkins/hash_build_properties.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Outputs to the stdout a deterministically generated integer in the range 0-4095. The integer is generated using the +# input strings and SHA1. +# Usage: hash_build_properties.sh +# Inputs: +# - branch: the branch being build +# - build_number the incrementing number of the build + +BRANCH=$1 +BUILD_NUMBER=$2 + +STRING_TO_HASH="$BRANCH-$BUILD_NUMBER" +SHA1_SUM_HEX=$(sha1sum <<<"$STRING_TO_HASH") +SHA1_TRUNCATED_HEX=$(cut -c1-3 <<<"$SHA1_SUM_HEX") +HASHED_STRING=$((0x${SHA1_TRUNCATED_HEX})) + +echo "$HASHED_STRING" diff --git a/jenkins/map_to_thousand.sh b/jenkins/map_to_thousand.sh new file mode 100755 index 0000000..d94d29d --- /dev/null +++ b/jenkins/map_to_thousand.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +INTEGER_TO_MAP=$1 + +echo $(( INTEGER_TO_MAP * 999 / 4095 )) diff --git a/migrations/1_initial_migration.js b/migrations/1_initial_migration.js deleted file mode 100644 index 4d5f3f9..0000000 --- a/migrations/1_initial_migration.js +++ /dev/null @@ -1,5 +0,0 @@ -var Migrations = artifacts.require("./Migrations.sol"); - -module.exports = function(deployer) { - deployer.deploy(Migrations); -}; diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js deleted file mode 100644 index feafc71..0000000 --- a/migrations/2_deploy_contracts.js +++ /dev/null @@ -1,5 +0,0 @@ -var Forum = artifacts.require("Forum"); - -module.exports = function(deployer) { - deployer.deploy(Forum); -}; \ No newline at end of file diff --git a/package.json b/package.json index 6ffc6e6..5c9bdd6 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,13 @@ { - "name": "apella", - "version": "0.1.0", + "name": "concordia", "private": true, - "repository": { - "type": "git", - "url": "https://gitlab.com/Ezerous/Apella.git" - }, - "devDependencies": { - "truffle-contract": "^3.0.4" - }, - "dependencies": { - "react": "^16.3.0", - "react-dom": "^16.3.0", - "react-scripts": "1.1.1", - "react-redux": "^5.0.7", - "react-router": "3.2.1", - "react-router-redux": "^4.0.8", - "redux": "^3.7.2", - "redux-auth-wrapper": "1.1.0", - "redux-thunk": "^2.2.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" + "workspaces": { + "packages": [ + "packages/*" + ], + "nohoist": [ + "**/web3", + "**/web3/**" + ] } } diff --git a/packages/concordia-app/.dockerignore b/packages/concordia-app/.dockerignore new file mode 100644 index 0000000..e69de29 diff --git a/packages/concordia-app/.env.development.example b/packages/concordia-app/.env.development.example new file mode 100644 index 0000000..4565811 --- /dev/null +++ b/packages/concordia-app/.env.development.example @@ -0,0 +1,11 @@ +# This is an example development configuration for the app +# To create your own configuration, copy this one and ommit the ".example" from the filename, then change the +# environment cariables to the prefered values. + +# Node dev-server host & port +HOST=localhost +PORT=7000 + +# Variables needed in runtime (in browser) +REACT_APP_RENDEZVOUS_HOST=127.0.0.1 +REACT_APP_RENDEZVOUS_PORT=9090 diff --git a/packages/concordia-app/.eslintrc.js b/packages/concordia-app/.eslintrc.js new file mode 100644 index 0000000..6c567d4 --- /dev/null +++ b/packages/concordia-app/.eslintrc.js @@ -0,0 +1,60 @@ +module.exports = { + 'env': { + 'browser': true, + 'es6': true, + 'jest': true + }, + 'extends': [ + 'plugin:react/recommended', + 'airbnb' + ], + 'globals': { + 'Atomics': 'readonly', + 'SharedArrayBuffer': 'readonly' + }, + parser: 'babel-eslint', + 'parserOptions': { + 'ecmaFeatures': { + 'jsx': true + }, + 'ecmaVersion': 2018, + 'sourceType': 'module' + }, + 'plugins': [ + 'react', + 'react-hooks', + ], + 'rules': { + 'react/jsx-props-no-spreading': 'off', + 'import/extensions': 'off', + "react/jsx-indent": [ + 'error', + 4, + { + checkAttributes: true, + indentLogicalExpressions: true + } + ], + 'react/require-default-props': 'off', + 'react/prop-types': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'error', + 'max-len': ['warn', {'code': 120, 'tabWidth': 4}], + 'no-unused-vars': 'warn', + 'no-console': ['warn', {allow: ['warn', 'error']}], + 'no-shadow': 'warn', + "no-multi-str": "warn", + "jsx-a11y/label-has-associated-control": [2, { + "labelAttributes": ["label"], + "controlComponents": ["Input"], + "depth": 3, + }], + }, + 'settings': { + 'import/resolver': { + 'node': { + 'extensions': ['.js', '.jsx'] + } + } + }, +}; diff --git a/packages/concordia-app/.gitignore b/packages/concordia-app/.gitignore new file mode 100644 index 0000000..74ef14b --- /dev/null +++ b/packages/concordia-app/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env +.env.local +.env.development +.env.development.local +.env.test +.env.test.local +.env.production +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/concordia-app/CONCORDIA.md b/packages/concordia-app/CONCORDIA.md new file mode 100644 index 0000000..59e0c48 --- /dev/null +++ b/packages/concordia-app/CONCORDIA.md @@ -0,0 +1,36 @@ +# Concordia + +The Concordia application is a React app that handles interactions with the contracts and the distributed database used. + +This document provides information about the Concordia React Application and how to get it running for development. + +## Prerequisites + +Concordia requires at the minimum two services to work, a blockchain and a rendezvous server. + +Furthermore, the deployed contract artifacts must be made available. This can be done in two ways, migrate the contracts +and make sure the artifacts are present in the `concordia/packages/concordia-contracts/build` directory, or migrate the +contracts and upload the artifacts to a contracts-provider instance. + +## Running Concordia + +To start the application in development mode simply execute the `start` script: +```shell +yarn start +``` + +The application makes use of the environment variables described below. + +| Environment variable | Default value | Usage | +| --- | --- | --- | +| REACT_APP_CONCORDIA_HOST | `127.0.0.1` | Set the hostname of the concordia application | +| REACT_APP_CONCORDIA_PORT | `7000` | Set the port of the concordia application | +| REACT_APP_RENDEZVOUS_HOST | `/ip4/127.0.0.1` | Set the hostname of the rendezvous server | +| REACT_APP_RENDEZVOUS_PORT | `9090` | Set the port of the rendezvous server | +| REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER | `false` | Enable/Disable use of external contracts provider | +| REACT_APP_CONTRACTS_PROVIDER_HOST | `http://127.0.0.1` | Set the hostname of the contracts provider service | +| REACT_APP_CONTRACTS_PROVIDER_PORT | `8400` | Set the port of the contracts provider service | +| REACT_APP_CONTRACTS_VERSION_HASH | `latest` | Set the contracts tag that will be pulled | + +**Attention**: if using a contracts provider, make sure that the provider is set to allow CORS from the host-port combo +defined by `REACT_APP_CONCORDIA_HOST` and `REACT_APP_CONCORDIA_PORT`. diff --git a/packages/concordia-app/package.json b/packages/concordia-app/package.json new file mode 100644 index 0000000..103506e --- /dev/null +++ b/packages/concordia-app/package.json @@ -0,0 +1,71 @@ +{ + "name": "concordia-app", + "version": "0.1.0", + "private": true, + "scripts": { + "start": "cross-env REACT_APP_VERSION=$npm_package_version REACT_APP_NAME=$npm_package_name react-scripts start", + "build": "cross-env REACT_APP_VERSION=$npm_package_version REACT_APP_NAME=$npm_package_name react-scripts build", + "test": "cross-env REACT_APP_VERSION=$npm_package_version REACT_APP_NAME=$npm_package_name react-scripts test", + "eject": "react-scripts eject", + "postinstall": "patch-package", + "analyze": "react-scripts build && source-map-explorer 'build/static/js/*.js' --gzip", + "lint": "eslint --ext js,jsx . --format table" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "dependencies": { + "@ecentrics/breeze": "~0.7.0", + "@ecentrics/drizzle": "~0.5.0", + "@ecentrics/eth-identity-provider": "~0.1.2", + "@reduxjs/toolkit": "~1.4.0", + "@welldone-software/why-did-you-render": "~6.0.5", + "apexcharts": "^3.26.0", + "concordia-contracts": "~0.1.0", + "concordia-shared": "~0.1.0", + "crypto-js": "~4.0.0", + "i18next": "^19.8.3", + "i18next-browser-languagedetector": "^6.0.1", + "i18next-http-backend": "^1.0.21", + "lodash": "^4.17.20", + "prop-types": "~15.7.2", + "react": "~16.13.1", + "react-apexcharts": "^1.3.7", + "react-avatar": "~3.9.7", + "react-copy-to-clipboard": "^5.0.3", + "react-dom": "~16.13.1", + "react-i18next": "^11.7.3", + "react-markdown": "^5.0.3", + "react-particles-js": "^3.4.0", + "react-redux": "~7.2.1", + "react-router": "^5.2.0", + "react-router-dom": "^5.2.0", + "react-scripts": "~3.4.3", + "react-timeago": "~5.2.0", + "redux-saga": "~1.1.3", + "semantic-ui-css": "~2.4.1", + "semantic-ui-react": "~2.0.3", + "web3": "~1.3.3" + }, + "devDependencies": { + "cross-env": "^7.0.3", + "eslint": "^6.8.0", + "eslint-config-airbnb": "^18.1.0", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^4.2.0", + "patch-package": "~6.2.2", + "postinstall-postinstall": "~2.1.0", + "source-map-explorer": "~2.5.0" + } +} diff --git a/packages/concordia-app/patches/web3-eth+1.3.4.patch b/packages/concordia-app/patches/web3-eth+1.3.4.patch new file mode 100644 index 0000000..165e6d5 --- /dev/null +++ b/packages/concordia-app/patches/web3-eth+1.3.4.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/web3-eth/lib/index.js b/node_modules/web3-eth/lib/index.js +index da8a65f..06d5f83 100644 +--- a/node_modules/web3-eth/lib/index.js ++++ b/node_modules/web3-eth/lib/index.js +@@ -288,8 +288,8 @@ var Eth = function Eth() { + this.Iban = Iban; + // add ABI + this.abi = abi; +- // add ENS +- this.ens = new ENS(this); ++ // add ENS (Removed because of https://github.com/ethereum/web3.js/issues/2665#issuecomment-687164093) ++ // this.ens = new ENS(this); + var methods = [ + new Method({ + name: 'getNodeInfo', diff --git a/packages/concordia-app/public/environment.js b/packages/concordia-app/public/environment.js new file mode 100644 index 0000000..e69de29 diff --git a/packages/concordia-app/public/favicon.ico b/packages/concordia-app/public/favicon.ico new file mode 100644 index 0000000..e246a57 Binary files /dev/null and b/packages/concordia-app/public/favicon.ico differ diff --git a/public/index.html b/packages/concordia-app/public/index.html similarity index 77% rename from public/index.html rename to packages/concordia-app/public/index.html index 2939b0d..cfd9385 100644 --- a/public/index.html +++ b/packages/concordia-app/public/index.html @@ -6,10 +6,10 @@ - - + + - Apella + Concordia + + - +