Skip to content

Commit

Permalink
Merge pull request #490 from Nezteb/master
Browse files Browse the repository at this point in the history
Add GitLab CI example with dialyzer cache, refactor sample CI configs into new docs directory
  • Loading branch information
jeremyjh committed Apr 13, 2023
2 parents 2d65f31 + b0102c5 commit fedbe91
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 55 deletions.
66 changes: 11 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,61 +65,12 @@ If invoked without arguments, `mix dialyzer.explain` will list all the known war

To use Dialyzer in CI, you must be aware of several things:

1) Building the PLT file may take a while if a project has many dependencies
2) The PLT should be cached using the CI caching system
3) The PLT will need to be rebuilt whenever adding a new Erlang or Elixir version to build matrix

### Github Actions

`dialyzer.yml`
```yaml
...
steps:
- uses: actions/checkout@v2
- name: Set up Elixir
id: beam
uses: erlef/setup-beam@v1
with:
elixir-version: "1.12.3" # Define the elixir version
otp-version: "24.1" # Define the OTP version

# Don't cache PLTs based on mix.lock hash, as Dialyzer can incrementally update even old ones
# Cache key based on Elixir & Erlang version (also useful when running in matrix)
- name: Restore PLT cache
uses: actions/cache/restore@v3
id: plt_cache
with:
key: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
restore-keys: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
path: |
priv/plts
# Create PLTs if no cache was found
- name: Create PLTs
if: steps.plt_cache.outputs.cache-hit != 'true'
run: mix dialyzer --plt

# By default, the GitHub Cache action will only save the cache if all steps in the job succeed,
# so we separate the cache restore and save steps in case running dialyzer fails.
- name: Save PLT cache
uses: actions/cache/save@v3
if: steps.plt_cache.outputs.cache-hit != 'true'
id: plt_cache_save
with:
key: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
path: |
priv/plts
- name: Run dialyzer
run: mix dialyzer --format github
1. Building the PLT file may take a while if a project has many dependencies
2. The PLT should be cached using the CI caching system
3. The PLT will need to be rebuilt whenever adding a new Erlang or Elixir version to your build matrix

```

`mix.exs`
```elixir
# mix.exs
def project do
[
...
Expand All @@ -130,12 +81,17 @@ def project do
end
```

`.gitignore`
```
```shell
# .gitignore
/priv/plts/*.plt
/priv/plts/*.plt.hash
```

### Example CI Configs

- [GitHub Actions](./docs/github_actions.md)
- [GitLab CI](./docs/gitlab_ci.md)

## With Explaining Stuff

[Dialyzer](http://www.erlang.org/doc/apps/dialyzer/dialyzer_chapter.html) is a static analysis tool for Erlang and other languages that compile to BEAM bytecode for the Erlang VM. It can analyze the BEAM files and provide warnings about problems in your code including type mismatches and other issues that are commonly detected by static language compilers. The analysis can be improved by inclusion of type hints (called [specs](https://hexdocs.pm/elixir/typespecs.html)) but it can be useful even without those. For more information I highly recommend the [Success Typings](http://user.it.uu.se/~kostis/Papers/succ_types.pdf) paper that describes the theory behind the tool.
Expand Down
49 changes: 49 additions & 0 deletions docs/github_actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Github Actions

```yaml
steps:
- name: Check out source
uses: actions/checkout@v2

- name: Set up Elixir
id: beam
uses: erlef/setup-beam@v1
with:
elixir-version: "1.12.3" # Define the Elixir version
otp-version: "24.1" # Define the OTP version

# Don't cache PLTs based on mix.lock hash, as Dialyzer can incrementally update even old ones
# Cache key based on Elixir & Erlang version (also useful when running in matrix)
- name: Restore PLT cache
id: plt_cache
uses: actions/cache/restore@v3
with:
key: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
restore-keys: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
path: |
priv/plts
# Create PLTs if no cache was found
- name: Create PLTs
if: steps.plt_cache.outputs.cache-hit != 'true'
run: mix dialyzer --plt

# By default, the GitHub Cache action will only save the cache if all steps in the job succeed,
# so we separate the cache restore and save steps in case running dialyzer fails.
- name: Save PLT cache
id: plt_cache_save
uses: actions/cache/save@v3
if: steps.plt_cache.outputs.cache-hit != 'true'
with:
key: |
${{ runner.os }}-${{ steps.beam.outputs.elixir-version }}-${{ steps.beam.outputs.otp-version }}-plt
path: |
priv/plts
- name: Run dialyzer
run: mix dialyzer --format github

# ...
```
67 changes: 67 additions & 0 deletions docs/gitlab_ci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# GitLab CI

```yaml
# Some of the duplication can be reduced with YAML anchors:
# https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html

image: elixir:1.14

stages:
- compile
- check-elixir-types

# You'll want to cache based on your Erlang/Elixir version.

# The example jobs below uses asdf's config file as the cache key:
# https://asdf-vm.com/manage/configuration.html

# An example build job with cache, to prevent dialyzer from needing to compile your project first
build-dev:
stage: compile
cache:
- key:
files:
- mix.lock
- .tool-versions
paths:
- deps/
- _build/dev
policy: pull-push
script:
- mix do deps.get, compile

# The main difference between the following jobs is their cache policy:
# https://docs.gitlab.com/ee/ci/yaml/index.html#cachepolicy

dialyzer-plt:
stage: check-elixir-types
needs:
- build-dev
cache:
- key:
files:
- .tool-versions
paths:
- priv/plts
# Pull cache at start, push updated cache after completion
policy: pull-push
script:
- mix dialyzer --plt

dialyzer-check:
stage: check-elixir-types
needs:
- dialyzer-plt
cache:
- key:
files:
- .tool-versions
paths:
- priv/plts
# Pull cache at start, don't push cache after completion
policy: pull
script:
- mix dialyzer --format short

# ...
```

0 comments on commit fedbe91

Please sign in to comment.