version: 2 jobs: build: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1-node-browsers environment: MIX_ENV: test # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres working_directory: ~/app steps: - run: sudo apt-get update; sudo apt-get -y install autoconf build-essential libgmp3-dev libtool - checkout - run: command: ./bin/install_chrome_headless.sh no_output_timeout: 2400 - run: mix local.hex --force - run: mix local.rebar --force - run: name: "ELIXIR_VERSION.lock" command: echo "${ELIXIR_VERSION}" > ELIXIR_VERSION.lock - run: name: "OTP_VERSION.lock" command: echo "${OTP_VERSION}" > OTP_VERSION.lock - restore_cache: keys: - v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }} - v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }} - v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }} - run: mix deps.get - restore_cache: keys: - v7-npm-install-{{ .Branch }}-{{ checksum "apps/block_scout_web/assets/package-lock.json" }} - v7-npm-install-{{ .Branch }} - v7-npm-install - run: command: npm install working_directory: "apps/explorer" - save_cache: key: v3-npm-install-{{ .Branch }}-{{ checksum "apps/explorer/package-lock.json" }} paths: "apps/explorer/node_modules" - save_cache: key: v3-npm-install-{{ .Branch }} paths: "apps/explorer/node_modules" - save_cache: key: v3-npm-install paths: "apps/explorer/node_modules" - run: command: npm install working_directory: "apps/block_scout_web/assets" - save_cache: key: v7-npm-install-{{ .Branch }}-{{ checksum "apps/block_scout_web/assets/package-lock.json" }} paths: "apps/block_scout_web/assets/node_modules" - save_cache: key: v7-npm-install-{{ .Branch }} paths: "apps/block_scout_web/assets/node_modules" - save_cache: key: v7-npm-install paths: "apps/block_scout_web/assets/node_modules" - run: mix compile # Ensure NIF is compiled for libsecp256k1 - run: command: make working_directory: "deps/libsecp256k1" # `deps` needs to be cached with `_build` because `_build` will symlink into `deps` - save_cache: key: v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }} paths: - deps - _build - save_cache: key: v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }} paths: - deps - _build - save_cache: key: v8-mix-compile-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }} paths: - deps - _build - run: name: Build assets command: node node_modules/webpack/bin/webpack.js --mode development working_directory: "apps/block_scout_web/assets" - persist_to_workspace: root: . paths: - .circleci - .credo.exs - .dialyzer-ignore - .formatter.exs - .git - .gitignore - ELIXIR_VERSION.lock - Gemfile - Gemfile.lock - OTP_VERSION.lock - _build - apps - bin - config - deps - doc - mix.exs - mix.lock - appspec.yml - rel check_formatted: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test working_directory: ~/app steps: - attach_workspace: at: . - run: mix format --check-formatted credo: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test working_directory: ~/app steps: - attach_workspace: at: . - run: mix local.hex --force - run: mix credo deploy_aws: docker: # Ensure .tool-versions matches - image: circleci/python:2.7-stretch working_directory: ~/app steps: - attach_workspace: at: . - add_ssh_keys: fingerprints: - "c4:fd:a8:f8:48:a8:09:e5:3e:be:30:62:4d:6f:6f:36" - run: name: Deploy to AWS command: bin/deploy dialyzer: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test working_directory: ~/app steps: - attach_workspace: at: . - run: mix local.hex --force - restore_cache: keys: - v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }} - v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }} - v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }} - run: name: Unpack PLT cache command: | mkdir -p _build/test cp plts/dialyxir*.plt _build/test/ || true mkdir -p ~/.mix cp plts/dialyxir*.plt ~/.mix/ || true - run: mix dialyzer --plt - run: name: Pack PLT cache command: | mkdir -p plts cp _build/test/dialyxir*.plt plts/ cp ~/.mix/dialyxir*.plt plts/ - save_cache: key: v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.lock" }} paths: - plts - save_cache: key: v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }}-{{ checksum "mix.exs" }} paths: - plts - save_cache: key: v8-mix-dialyzer-{{ checksum "OTP_VERSION.lock" }}-{{ checksum "ELIXIR_VERSION.lock" }} paths: - plts - run: mix dialyzer --halt-exit-status eslint: docker: # Ensure .tool-versions matches - image: circleci/node:12.13.0-browsers-legacy working_directory: ~/app steps: - attach_workspace: at: . - run: name: ESLint command: ./node_modules/.bin/eslint --format=junit --output-file="test/eslint/junit.xml" js/** working_directory: apps/block_scout_web/assets - store_test_results: path: apps/block_scout_web/assets/test gettext: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test working_directory: ~/app steps: - attach_workspace: at: . - run: mix local.hex --force - run: name: Check for missed translations command: | mix gettext.extract --merge | tee stdout.txt ! grep "Wrote " stdout.txt working_directory: "apps/block_scout_web" - store_artifacts: path: apps/block_scout_web/priv/gettext jest: docker: # Ensure .tool-versions matches - image: circleci/node:12.13.0-browsers-legacy working_directory: ~/app steps: - attach_workspace: at: . - run: name: Jest command: ./node_modules/.bin/jest working_directory: apps/block_scout_web/assets release: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: prod working_directory: ~/app steps: - attach_workspace: at: . - run: mix local.hex --force - run: mix local.rebar --force - run: MIX_ENV=prod mix release - run: name: Collecting artifacts command: | find -name 'blockscout.tar.gz' -exec sh -c 'mkdir -p ci_artifact && cp "$@" ci_artifact/ci_artifact_blockscout.tar.gz' _ {} + when: always - store_artifacts: name: Uploading CI artifacts path: ci_artifact/ci_artifact_blockscout.tar.gz destination: ci_artifact_blockscout.tar.gz sobelow: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test working_directory: ~/app steps: - attach_workspace: at: . - run: mix local.hex --force - run: name: Scan explorer for vulnerabilities command: mix sobelow --config working_directory: "apps/explorer" - run: name: Scan block_scout_web for vulnerabilities command: mix sobelow --config working_directory: "apps/block_scout_web" # test_geth_http_websocket: # docker: # # Ensure .tool-versions matches # - image: circleci/elixir:1.9.1-node-browsers # environment: # MIX_ENV: test # # match POSTGRES_PASSWORD for postgres image below # PGPASSWORD: postgres # # match POSTGRES_USER for postgres image below # PGUSER: postgres # ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Geth.HTTPWebSocket" # ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Geth" # - image: circleci/postgres:10.3-alpine # environment: # # Match apps/explorer/config/test.exs config :explorer, Explorer.Repo, database # POSTGRES_DB: explorer_test # # match PGPASSWORD for elixir image above # POSTGRES_PASSWORD: postgres # # match PGUSER for elixir image above # POSTGRES_USER: postgres # working_directory: ~/app # steps: # - attach_workspace: # at: . # - run: # command: ./bin/install_chrome_headless.sh # no_output_timeout: 2400 # - run: mix local.hex --force # - run: mix local.rebar --force # - run: # name: Wait for DB # command: dockerize -wait tcp://localhost:5432 -timeout 1m # - run: # name: mix test --exclude no_geth # command: | # # Don't submit coverage report for forks, but let the build succeed # if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then # mix coveralls.html --exclude no_geth --parallel --umbrella # else # mix coveralls.circle --exclude no_geth --parallel --umbrella || # # if mix failed, then coveralls_merge won't run, so signal done here and return original exit status # (retval=$? && curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$CIRCLE_WORKFLOW_WORKSPACE_ID&payload[status]=done" && return $retval) # fi # - store_artifacts: # path: cover/excoveralls.html # - store_test_results: # path: _build/test/junit # test_geth_mox: # docker: # # Ensure .tool-versions matches # - image: circleci/elixir:1.9.1-node-browsers # environment: # MIX_ENV: test # # match POSTGRES_PASSWORD for postgres image below # PGPASSWORD: postgres # # match POSTGRES_USER for postgres image below # PGUSER: postgres # ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Geth.Mox" # ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" # - image: circleci/postgres:10.3-alpine # environment: # # Match apps/explorer/config/test.exs config :explorer, Explorer.Repo, database # POSTGRES_DB: explorer_test # # match PGPASSWORD for elixir image above # POSTGRES_PASSWORD: postgres # # match PGUSER for elixir image above # POSTGRES_USER: postgres # working_directory: ~/app # steps: # - attach_workspace: # at: . # - run: # command: ./bin/install_chrome_headless.sh # no_output_timeout: 2400 # - run: mix local.hex --force # - run: mix local.rebar --force # - run: # name: Wait for DB # command: dockerize -wait tcp://localhost:5432 -timeout 1m # - run: # name: mix test --exclude no_geth # command: | # # Don't submit coverage report for forks, but let the build succeed # if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then # mix coveralls.html --exclude no_geth --parallel --umbrella # else # mix coveralls.circle --exclude no_geth --parallel --umbrella || # # if mix failed, then coveralls_merge won't run, so signal done here and return original exit status # (retval=$? && curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$CIRCLE_WORKFLOW_WORKSPACE_ID&payload[status]=done" && return $retval) # fi # - store_artifacts: # path: cover/excoveralls.html # - store_test_results: # path: _build/test/junit # test_parity_http_websocket: # docker: # # Ensure .tool-versions matches # - image: circleci/elixir:1.9.1-node-browsers # environment: # MIX_ENV: test # # match POSTGRES_PASSWORD for postgres image below # PGPASSWORD: postgres # # match POSTGRES_USER for postgres image below # PGUSER: postgres # ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Parity.HTTPWebSocket" # ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Parity" # - image: circleci/postgres:10.3-alpine # environment: # # Match apps/explorer/config/test.exs config :explorer, Explorer.Repo, database # POSTGRES_DB: explorer_test # # match PGPASSWORD for elixir image above # POSTGRES_PASSWORD: postgres # # match PGUSER for elixir image above # POSTGRES_USER: postgres # working_directory: ~/app # steps: # - attach_workspace: # at: . # - run: # command: ./bin/install_chrome_headless.sh # no_output_timeout: 2400 # - run: mix local.hex --force # - run: mix local.rebar --force # - run: # name: Wait for DB # command: dockerize -wait tcp://localhost:5432 -timeout 1m # - run: # name: mix test --exclude no_parity # command: | # # Don't submit coverage report for forks, but let the build succeed # if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then # mix coveralls.html --exclude no_parity --parallel --umbrella # else # mix coveralls.circle --exclude no_parity --parallel --umbrella || # # if mix failed, then coveralls_merge won't run, so signal done here and return original exit status # (retval=$? && curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$CIRCLE_WORKFLOW_WORKSPACE_ID&payload[status]=done" && return $retval) # fi # - store_artifacts: # path: cover/excoveralls.html # - store_test_results: # path: _build/test/junit test_parity_mox: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1-node-browsers environment: MIX_ENV: test # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Parity.Mox" ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" - image: circleci/postgres:10.3-alpine environment: # Match apps/explorer/config/test.exs config :explorer, Explorer.Repo, database POSTGRES_DB: explorer_test # match PGPASSWORD for elixir image above POSTGRES_PASSWORD: postgres # match PGUSER for elixir image above POSTGRES_USER: postgres working_directory: ~/app steps: - attach_workspace: at: . - run: command: ./bin/install_chrome_headless.sh no_output_timeout: 2400 - run: mix local.hex --force - run: mix local.rebar --force - run: name: Wait for DB command: dockerize -wait tcp://localhost:5432 -timeout 1m - run: name: mix test --exclude no_parity command: | # Don't submit coverage report for forks, but let the build succeed if [[ -z "$COVERALLS_REPO_TOKEN" ]]; then mix coveralls.html --exclude no_parity --parallel --umbrella else mix coveralls.circle --exclude no_parity --parallel --umbrella || # if mix failed, then coveralls_merge won't run, so signal done here and return original exit status (retval=$? && curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$CIRCLE_WORKFLOW_WORKSPACE_ID&payload[status]=done" && return $retval) fi - store_artifacts: path: cover/excoveralls.html - store_test_results: path: _build/test/junit coveralls_merge: docker: # Ensure .tool-versions matches - image: circleci/elixir:1.9.1 environment: MIX_ENV: test steps: - run: name: Tell coveralls.io build is done command: curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$CIRCLE_WORKFLOW_WORKSPACE_ID&payload[status]=done" workflows: version: 2 primary: jobs: - build - check_formatted: requires: - build # This unfortunately will only fire if all the tests pass because of how `requires` works - coveralls_merge: requires: # - test_parity_http_websocket - test_parity_mox # - test_geth_http_websocket # - test_geth_mox - credo: requires: - build - deploy_aws: filters: branches: only: - production - staging - /deploy-[A-Za-z0-9]+$/ requires: - check_formatted - credo - eslint - jest - sobelow # - test_parity_http_websocket - test_parity_mox # - test_geth_http_websocket # - test_geth_mox - dialyzer: requires: - build - eslint: requires: - build - gettext: requires: - build - jest: requires: - build - release: requires: - build - sobelow: requires: - build # - test_parity_http_websocket: # requires: # - build - test_parity_mox: requires: - build # - test_geth_http_websocket: # requires: # - build # - test_geth_mox: # requires: # - build