name: Blockscout on: push: branches: - master - production-core-stg - production-eth-stg-experimental - production-eth-goerli-stg - production-eth-sepolia-stg - production-fuse-stg - production-optimism-stg - production-immutable-stg - production-iota-stg - production-lukso-stg - production-rsk-stg - production-sokol-stg - production-suave-stg - production-xdai-stg - production-zkevm-stg - production-zksync-stg - staging-l2 pull_request: branches: - master - production-optimism-stg env: MIX_ENV: test OTP_VERSION: '25.2.1' ELIXIR_VERSION: '1.14.5' ACCOUNT_AUTH0_DOMAIN: 'blockscoutcom.us.auth0.com' jobs: build-and-cache: name: Build and Cache deps runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: "ELIXIR_VERSION.lock" run: echo "${ELIXIR_VERSION}" > ELIXIR_VERSION.lock - name: "OTP_VERSION.lock" run: echo "${OTP_VERSION}" > OTP_VERSION.lock - name: Restore Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps- - name: Conditionally build Mix deps cache if: steps.deps-cache.outputs.cache-hit != 'true' run: | mix local.hex --force mix local.rebar --force mix deps.get mix deps.compile - name: Restore Explorer NPM Cache uses: actions/cache@v2 id: explorer-npm-cache with: path: apps/explorer/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm- - name: Conditionally build Explorer NPM Cache if: steps.explorer-npm-cache.outputs.cache-hit != 'true' run: npm install working-directory: apps/explorer - name: Restore Blockscout Web NPM Cache uses: actions/cache@v2 id: blockscoutweb-npm-cache with: path: apps/block_scout_web/assets/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm- - name: Conditionally build Blockscout Web NPM Cache if: steps.blockscoutweb-npm-cache.outputs.cache-hit != 'true' run: npm install working-directory: apps/block_scout_web/assets credo: name: Credo runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Restore Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - run: mix credo check_formatted: name: Code formatting checks runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Restore Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - run: mix format --check-formatted dialyzer: name: Dialyzer static analysis runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Restore Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Dialyzer Cache uses: actions/cache@v2 id: dialyzer-cache with: path: priv/plts key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-dialyzer-mixlockhash_25-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-dialyzer-" - name: Conditionally build Dialyzer Cache if: steps.dialyzer-cache.output.cache-hit != 'true' run: | mkdir -p priv/plts mix dialyzer --plt - name: Run Dialyzer run: mix dialyzer --halt-exit-status gettext: name: Missing translation keys check runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Restore Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - run: | mix gettext.extract --merge | tee stdout.txt ! grep "Wrote " stdout.txt working-directory: "apps/block_scout_web" sobelow: name: Sobelow security analysis runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Scan explorer for vulnerabilities run: mix sobelow --config working-directory: "apps/explorer" - name: Scan block_scout_web for vulnerabilities run: mix sobelow --config working-directory: "apps/block_scout_web" cspell: name: Check spelling runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Explorer NPM Cache uses: actions/cache@v2 id: explorer-npm-cache with: path: apps/explorer/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm- - name: Restore Blockscout Web NPM Cache uses: actions/cache@v2 id: blockscoutweb-npm-cache with: path: apps/block_scout_web/assets/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm- - name: Run cspell uses: streetsidesoftware/cspell-action@v2 with: files: | **/*.ex* **/*.eex **/*.js" eslint: name: ESLint runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Explorer NPM Cache uses: actions/cache@v2 id: explorer-npm-cache with: path: apps/explorer/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm- - name: Restore Blockscout Web NPM Cache uses: actions/cache@v2 id: blockscoutweb-npm-cache with: path: apps/block_scout_web/assets/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm- - name: Build assets run: node node_modules/webpack/bin/webpack.js --mode development working-directory: "apps/block_scout_web/assets" - run: ./node_modules/.bin/eslint --format=junit --output-file="test/eslint/junit.xml" js/** working-directory: apps/block_scout_web/assets jest: name: JS Tests runs-on: ubuntu-latest needs: build-and-cache steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Blockscout Web NPM Cache uses: actions/cache@v2 id: blockscoutweb-npm-cache with: path: apps/block_scout_web/assets/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm- - name: Build assets run: node node_modules/webpack/bin/webpack.js --mode development working-directory: "apps/block_scout_web/assets" - run: ./node_modules/.bin/jest working-directory: apps/block_scout_web/assets test_nethermind_mox_ethereum_jsonrpc: name: EthereumJSONRPC Tests runs-on: ubuntu-latest needs: build-and-cache services: postgres: image: postgres env: # 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 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: # Maps tcp port 5432 on service container to the host - 5432:5432 steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - run: ./bin/install_chrome_headless.sh - name: mix test --exclude no_nethermind run: | cd apps/ethereum_jsonrpc mix compile mix test --no-start --exclude no_nethermind env: # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox" ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" test_nethermind_mox_explorer: name: Explorer Tests runs-on: ubuntu-latest needs: build-and-cache services: postgres: image: postgres env: # 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 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: # Maps tcp port 5432 on service container to the host - 5432:5432 steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Explorer NPM Cache uses: actions/cache@v2 id: explorer-npm-cache with: path: apps/explorer/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm - run: ./bin/install_chrome_headless.sh - name: mix test --exclude no_nethermind run: | mix ecto.create --quiet mix ecto.migrate cd apps/explorer mix compile mix test --no-start --exclude no_nethermind env: # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox" ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" test_nethermind_mox_indexer: name: Indexer Tests runs-on: ubuntu-latest needs: build-and-cache services: postgres: image: postgres env: # 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 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: # Maps tcp port 5432 on service container to the host - 5432:5432 steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - run: ./bin/install_chrome_headless.sh - name: mix test --exclude no_nethermind run: | mix ecto.create --quiet mix ecto.migrate cd apps/indexer mix compile mix test --no-start --exclude no_nethermind env: # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox" ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" test_nethermind_mox_block_scout_web: name: Blockscout Web Tests runs-on: ubuntu-latest needs: build-and-cache services: redis_db: image: 'redis:alpine' ports: - 6379:6379 postgres: image: postgres env: # 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 # Set health checks to wait until postgres has started options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: # Maps tcp port 5432 on service container to the host - 5432:5432 steps: - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} elixir-version: ${{ env.ELIXIR_VERSION }} - name: Mix Deps Cache uses: actions/cache@v2 id: deps-cache with: path: | deps _build key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" - name: Restore Explorer NPM Cache uses: actions/cache@v2 id: explorer-npm-cache with: path: apps/explorer/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm- - name: Restore Blockscout Web NPM Cache uses: actions/cache@v2 id: blockscoutweb-npm-cache with: path: apps/block_scout_web/assets/node_modules key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm- - name: Build assets run: node node_modules/webpack/bin/webpack.js --mode development working-directory: "apps/block_scout_web/assets" - run: ./bin/install_chrome_headless.sh - name: mix test --exclude no_nethermind run: | mix ecto.create --quiet mix ecto.migrate cd apps/block_scout_web mix compile mix test --no-start --exclude no_nethermind env: # match POSTGRES_PASSWORD for postgres image below PGPASSWORD: postgres # match POSTGRES_USER for postgres image below PGUSER: postgres ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox" ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox" CHAIN_ID: "10200" API_RATE_LIMIT_DISABLED: "true" ADMIN_PANEL_ENABLED: "true" ACCOUNT_ENABLED: "true" ACCOUNT_REDIS_URL: "redis://localhost:6379" SOURCIFY_INTEGRATION_ENABLED: "true"