Define CI workflow to be directly usable when cloning #78
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Continuous integration | ||
| # Running on the branch main and on all PRs | ||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| pull_request: | ||
| jobs: | ||
| # TODO: Split this job in multiple jobs to group similar tasks together (like setup, audit dependencies, format, lint, tests, etc...) | ||
| # It would be nice if the setup could be reused, so it doesn't need to happen in every job (https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts) | ||
| continuous_integration: | ||
| name: Continuous integration | ||
| runs-on: ubuntu-24.04 | ||
| env: | ||
| MIX_ENV: test | ||
| # CHANGEME: Remove or adapt this service based on your project needs | ||
| services: | ||
| # Database for the test suite, be sure to use the same Docker image in docker-compose.yml | ||
| postgres: | ||
| image: postgres:18.0 | ||
| env: | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: postgres | ||
| POSTGRES_DB: database_test | ||
| options: >- | ||
| --health-cmd pg_isready | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
| ports: | ||
| - 5432:5432 | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v6 | ||
| - name: Read Elixir and Erlang versions from mise.toml | ||
| id: versions | ||
| run: | | ||
| echo "elixir=$(sed -n 's|elixir = \"\(.*\)\"|\1|p' mise.toml)" >> "$GITHUB_OUTPUT" | ||
| echo "erlang=$(sed -n 's|erlang = \"\(.*\)\"|\1|p' mise.toml)" >> "$GITHUB_OUTPUT" | ||
| - name: Setup Elixir and Erlang | ||
| uses: erlef/setup-beam@v1 | ||
| id: setup-beam | ||
| with: | ||
| otp-version: ${{ steps.versions.outputs.erlang }} | ||
| elixir-version: ${{ steps.versions.outputs.elixir }} | ||
| # Whenever a cache hit occurs for the exact `key` match defined below, this step sets the `cache-hit` outputs to 'true'. | ||
| # With `if: steps.cache-deps.outputs.cache-hit != 'true'`, this can be used in steps to run or ignore them based on the cache hit. | ||
| # A partial key match via `restore-keys` or a cache miss will set `cache-hit` to 'false'. | ||
| - name: Restore dependencies from cache if possible | ||
| uses: actions/cache@v5 | ||
| id: cache-deps | ||
| env: | ||
| cache-name: deps-${{ runner.os }}-${{ steps.setup-beam.outputs.otp-version }}-${{ steps.setup-beam.outputs.elixir-version }}- | ||
| with: | ||
| # deps -> where Mix downloads dependencies | ||
| path: deps | ||
| key: ${{ env.cache-name }}${{ hashFiles('**/mix.lock') }} | ||
| restore-keys: | | ||
| ${{ env.cache-name }} | ||
| # Whenever a cache hit occurs for the exact `key` match defined below, this step sets the `cache-hit` outputs to 'true'. | ||
| # With `if: steps.cache-build.outputs.cache-hit != 'true'`, this can be used in steps to run or ignore them based on the cache hit. | ||
| # A partial key match via `restore-keys` or a cache miss will set `cache-hit` to 'false'. | ||
| - name: Restore build from cache if possible | ||
| uses: actions/cache@v5 | ||
| id: cache-build | ||
| env: | ||
| cache-name: build-${{ runner.os }}-${{ steps.setup-beam.outputs.otp-version }}-${{ steps.setup-beam.outputs.elixir-version }}- | ||
| with: | ||
| # _build -> where Mix stores compiled artifacts | ||
| path: _build | ||
| key: ${{ env.cache-name }}${{ hashFiles('**/mix.lock') }} | ||
| restore-keys: | | ||
| ${{ env.cache-name }} | ||
| - name: Install and compile dependencies # https://hexdocs.pm/mix/Mix.Tasks.Deps.Get.html & https://hexdocs.pm/mix/Mix.Tasks.Deps.Compile.html | ||
| run: mix do deps.get + deps.compile | ||
| - name: Find unused dependencies # https://hexdocs.pm/mix/Mix.Tasks.Deps.Unlock.html | ||
| run: mix deps.unlock --check-unused | ||
| - name: Check for retired dependencies # https://hexdocs.pm/hex/Mix.Tasks.Hex.Audit.html | ||
| run: mix hex.audit | ||
| - name: Check for vulnerable dependencies # https://github.com/mirego/mix_audit | ||
| run: mix deps.audit | ||
| - name: Ensure Elixir code is formatted # https://hexdocs.pm/mix/Mix.Tasks.Format.html | ||
| run: mix format --check-formatted | ||
| - name: Ensure the Elixir code compiles # https://hexdocs.pm/mix/Mix.Tasks.Compile.html | ||
| run: mix compile --all-warnings --warning-as-errors | ||
| - name: Lint Elixir code to enforce code consistency # Credo's strict analysis: https://hexdocs.pm/credo/basic_usage.html#strict-analysis | ||
| run: mix credo --strict | ||
| - name: Check Elixir code for security vulnerabilities # https://github.com/nccgroup/sobelow | ||
| # `--private` is to prevent Sobelow from checking for updates, this does not belong in the CI | ||
| run: mix sobelow --private | ||
| - name: Check Elixir code for type mismatches, unreachable code and other issues # https://hexdocs.pm/dialyxir/Mix.Tasks.Dialyzer.html | ||
| run: mix dialyzer --list-unused-filters --format github | ||
| - name: Verify database migrations and if they can fully rollback # https://hexdocs.pm/ecto_sql/Mix.Tasks.Ecto.Rollback.html | ||
| run: mix ecto.create && mix ecto.migrate && mix ecto.rollback --all | ||
| - name: Run tests # https://hexdocs.pm/mix/Mix.Tasks.Test.html | ||
| run: mix test | ||