diff --git a/.env b/.env new file mode 100644 index 0000000..f52538f --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +OTP_VERSION=24 +REBAR_VERSION=3.18 +THRIFT_VERSION=0.14.2.3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index de3dd09..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,155 +0,0 @@ -name: Erlang Library CI - -on: - push: - branches: [ master ] - pull_request: - branches: [ '**' ] - -env: - OTP_VERSION: 24.2 - REBAR_VERSION: 3.18 - THRIFT_VERSION: 0.14.2.1 - -jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup BEAM - uses: erlef/setup-beam@v1.10 - with: - otp-version: ${{ env.OTP_VERSION }} - rebar3-version: ${{ env.REBAR_VERSION }} - - - name: Cache _build - uses: actions/cache@v2 - with: - path: _build/*/lib - key: ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build-${{ hashFiles('rebar.lock') }} - restore-keys: | - ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build- - - - name: Compile - run: rebar3 compile - - check: - name: Check - runs-on: ubuntu-latest - needs: build - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup BEAM - uses: erlef/setup-beam@v1.10 - with: - otp-version: ${{ env.OTP_VERSION }} - rebar3-version: ${{ env.REBAR_VERSION }} - - - name: Cache _build - uses: actions/cache@v2 - with: - path: _build/*/lib - key: ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build-${{ hashFiles('rebar.lock') }} - restore-keys: | - ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build- - - - name: Check formatting - run: rebar3 fmt -c - - - name: Run linting - run: rebar3 lint - - - name: Run xref - run: rebar3 xref - - dialyze: - name: Dialyze - needs: build - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup Thrift compiler - uses: valitydev/action-setup-thrift@v0.0.5 - with: - thrift-version: ${{ env.THRIFT_VERSION }} - - - name: Setup BEAM - uses: erlef/setup-beam@v1.10 - with: - otp-version: ${{ env.OTP_VERSION }} - rebar3-version: ${{ env.REBAR_VERSION }} - - - name: Cache _build - uses: actions/cache@v2 - with: - path: _build/*/lib - key: ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build-${{ hashFiles('rebar.lock') }} - restore-keys: | - ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build- - - - name: Cache PLTs - uses: actions/cache@v2 - with: - path: _build/test/rebar3_*_plt - key: ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-plt-${{ hashFiles('rebar.lock') }} - restore-keys: | - ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-plt- - - - name: Run dialyzer - run: rebar3 as test dialyzer - - test: - name: Test - needs: build - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup Thrift compiler - uses: valitydev/action-setup-thrift@v0.0.5 - with: - thrift-version: ${{ env.THRIFT_VERSION }} - - - name: Setup BEAM - uses: erlef/setup-beam@v1.10 - with: - otp-version: ${{ env.OTP_VERSION }} - rebar3-version: ${{ env.REBAR_VERSION }} - - - name: Cache _build - uses: actions/cache@v2 - with: - path: _build/*/lib - key: ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build-${{ hashFiles('rebar.lock') }} - restore-keys: | - ${{ runner.os }}-otp-${{ env.OTP_VERSION }}-build- - - - name: Run EUnit - run: rebar3 eunit --cover - - - name: Run CT - id: run-common-test - run: rebar3 ct --cover - - - name: Store CT Logs - if: ${{ failure() && steps.run-common-test.outcome == 'failure' }} - uses: actions/upload-artifact@v2 - with: - name: ct-logs - path: _build/test/logs - - - name: Generate coverage reports - run: rebar3 covertool generate - - - name: Upload coverage reports - uses: codecov/codecov-action@v2 - with: - files: _build/test/covertool/*.covertool.xml diff --git a/.github/workflows/erlang-checks.yml b/.github/workflows/erlang-checks.yml new file mode 100644 index 0000000..d701276 --- /dev/null +++ b/.github/workflows/erlang-checks.yml @@ -0,0 +1,38 @@ +name: Erlang CI Checks + +on: + push: + branches: + - 'master' + - 'epic/**' + pull_request: + branches: ['**'] + +jobs: + setup: + name: Load .env + runs-on: ubuntu-latest + outputs: + otp-version: ${{ steps.otp-version.outputs.version }} + rebar-version: ${{ steps.rebar-version.outputs.version }} + thrift-version: ${{ steps.thrift-version.outputs.version }} + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - run: grep -v '^#' .env >> $GITHUB_ENV + - id: otp-version + run: echo "::set-output name=version::$OTP_VERSION" + - id: rebar-version + run: echo "::set-output name=version::$REBAR_VERSION" + - id: thrift-version + run: echo "::set-output name=version::$THRIFT_VERSION" + + run: + name: Run checks + needs: setup + uses: valitydev/erlang-workflows/.github/workflows/erlang-parallel-build.yml@v1.0.9 + with: + otp-version: ${{ needs.setup.outputs.otp-version }} + rebar-version: ${{ needs.setup.outputs.rebar-version }} + use-thrift: true + thrift-version: ${{ needs.setup.outputs.thrift-version }} diff --git a/.gitignore b/.gitignore index 56d4c17..658bd95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,14 @@ -# general -log +# Build artifacts /_build/ -/_checkouts/ -*~ +*.o +*.beam +*.plt + +# Run artifacts erl_crash.dump -.tags* -*.sublime-workspace -.edts -.DS_Store -.rebar3/ -ebin/ -docker-compose.yml +log test/woody_test_thrift.* + +# make stuff +/.image.* +Makefile.env diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..353a6a0 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,13 @@ +ARG OTP_VERSION + +FROM docker.io/library/erlang:${OTP_VERSION} +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# Install thrift compiler +ARG THRIFT_VERSION +ARG TARGETARCH +RUN wget -q -O- "https://github.com/valitydev/thrift/releases/download/${THRIFT_VERSION}/thrift-${THRIFT_VERSION}-linux-${TARGETARCH}.tar.gz" \ + | tar -xvz -C /usr/local/bin/ + +# Set runtime +CMD ["/bin/bash"] diff --git a/Makefile b/Makefile index 3f550d3..aca236f 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,97 @@ -REBAR := $(shell which rebar3 2>/dev/null || which ./rebar3) +# HINT +# Use this file to override variables here. +# For example, to run with podman put `DOCKER=podman` there. +-include Makefile.env -.PHONY: compile test xref lint check_format format clean distclean dialyze cover bench +# NOTE +# Variables specified in `.env` file are used to pick and setup specific +# component versions, both when building a development image and when running +# CI workflows on GH Actions. This ensures that tasks run with `wc-` prefix +# (like `wc-dialyze`) are reproducible between local machine and CI runners. +DOTENV := $(shell grep -v '^\#' .env) + +DOCKER ?= docker +REBAR ?= rebar3 +TEST_CONTAINER_NAME ?= woody + +all: compile + +# Development images + +DEV_IMAGE_TAG = $(TEST_CONTAINER_NAME)-dev +DEV_IMAGE_ID = $(file < .image.dev) + +.PHONY: dev-image clean-dev-image wc-shell test + +dev-image: .image.dev + +.image.dev: Dockerfile.dev .env + $(DOCKER) build . -f Dockerfile.dev --tag $(DEV_IMAGE_TAG) $(DOTENV:%=--build-arg %) + $(DOCKER) image ls -q -f "reference=$(DEV_IMAGE_TAG)" | head -n1 > $@ + +clean-dev-image: +ifneq ($(DEV_IMAGE_ID),) + $(DOCKER) image rm -f $(DEV_IMAGE_TAG) + rm .image.dev +endif + +DOCKER_WC_OPTIONS := -v $(PWD):$(PWD) --workdir $(PWD) +DOCKER_WC_EXTRA_OPTIONS ?= --rm +DOCKER_RUN = $(DOCKER) run -t $(DOCKER_WC_OPTIONS) $(DOCKER_WC_EXTRA_OPTIONS) + +# Utility tasks + +wc-shell: dev-image + $(DOCKER_RUN) --interactive --tty $(DEV_IMAGE_TAG) + +wc-%: dev-image + $(DOCKER_RUN) $(DEV_IMAGE_TAG) make $* + +# Rebar tasks + +rebar-shell: + $(REBAR) shell compile: $(REBAR) compile -test: - $(REBAR) eunit - $(REBAR) ct - xref: $(REBAR) xref lint: $(REBAR) lint -check_format: +check-format: $(REBAR) fmt -c +dialyze: + $(REBAR) as test dialyzer + +release: + $(REBAR) as prod release + +eunit: + $(REBAR) eunit --cover + +common-test: + $(REBAR) ct --cover + +cover: + $(REBAR) covertool generate + format: $(REBAR) fmt -w clean: $(REBAR) clean - $(REBAR) as test clean - $(REBAR) as prod clean -distclean: - rm -rf test/woody_test_thrift.?rl test/.rebar3 - rm -rfv _build +distclean: clean-build-image + rm -rf _build -dialyze: - $(REBAR) as test dialyzer +test: eunit common-test -cover: +cover-report: $(REBAR) cover - $(REBAR) covertool generate bench: $(REBAR) as test bench -m bench_woody_event_handler -n 1000 diff --git a/elvis.config b/elvis.config index ad33777..549fc41 100644 --- a/elvis.config +++ b/elvis.config @@ -1,5 +1,6 @@ [ {elvis, [ + {verbose, true}, {config, [ #{ dirs => ["src", "include", "test"], @@ -54,7 +55,7 @@ filter => "rebar.config", ruleset => rebar_config, rules => [ - {elvis_text_style, line_length, #{limit => 120, skip_comments => false}}, + {elvis_text_style, line_length, #{limit => 120}}, {elvis_text_style, no_tabs}, {elvis_text_style, no_trailing_whitespace}, %% Temporarily disabled till regex pattern is available @@ -65,7 +66,7 @@ dirs => ["src"], filter => "*.app.src", rules => [ - {elvis_text_style, line_length, #{limit => 120, skip_comments => false}}, + {elvis_text_style, line_length, #{limit => 120}}, {elvis_text_style, no_tabs}, {elvis_text_style, no_trailing_whitespace} ] diff --git a/rebar.config b/rebar.config index c8829ea..41578e7 100644 --- a/rebar.config +++ b/rebar.config @@ -1,5 +1,6 @@ -% Common project erlang options. +%% Common project erlang options. {erl_opts, [ + % mandatory debug_info, warnings_as_errors, warn_export_all, @@ -16,6 +17,11 @@ warn_unused_import, warn_unused_function, warn_deprecated_function + + % at will + % bin_opt_info + % no_auto_import + % warn_missing_spec_all ]}. % Common project dependencies. @@ -29,16 +35,20 @@ {genlib, {git, "https://github.com/valitydev/genlib.git", {branch, "master"}}} ]}. +%% XRef checks {xref_checks, [ undefined_function_calls, undefined_functions, - locals_not_used, deprecated_functions_calls, deprecated_functions ]}. +% at will +% {xref_warnings, true}. +%% Dialyzer static analyzing {dialyzer, [ {warnings, [ + % mandatory unmatched_returns, error_handling, race_conditions, @@ -85,21 +95,19 @@ ]} ]}. -{plugins, [ +{project_plugins, [ {rebar3_thrift_compiler, {git, "https://github.com/valitydev/rebar3_thrift_compiler.git", {tag, "0.3.1"}}}, {erlfmt, "1.0.0"}, {rebar3_lint, "1.0.1"}, {covertool, "2.0.4"} ]}. +%% Linter config. +{elvis_output_format, colors}. + {erlfmt, [ {print_width, 120}, - {files, [ - "{src,include}/*.{hrl,erl}", - "test/*.{hrl,erl}", - "rebar.config", - "elvis.config" - ]} + {files, ["{src,include,test}/*.{hrl,erl}", "rebar.config", "elvis.config"]} ]}. {covertool, [