Skip to content

Commit

Permalink
Add GitHub Actions CI (#181)
Browse files Browse the repository at this point in the history
* Add GitHub Actions CI

Adds GitHub Actions for:

- build & test for all combinations of Elixir 1.10, 1.11, 1.12, 1.13, 1.14, and 1.15, plus OTP 22, 23, 24, 25, and 26
- basic code quality checks (and a formatting fix and unused dependency removal to match)
- checking for retired Hex dependencies

Also updates the maintainers list and URL to reflect the new Felt org.

* Run mix format

* Fix build & test action

* Test a failure case discovered by the test matrix
  • Loading branch information
s3cur3 authored Sep 14, 2023
1 parent cda5bba commit 219e76d
Show file tree
Hide file tree
Showing 17 changed files with 390 additions and 30 deletions.
141 changes: 141 additions & 0 deletions .github/actions/elixir-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Setup Elixir Project
description: Checks out the code, configures Elixir, fetches dependencies, and manages build caching.
inputs:
elixir-version:
required: true
type: string
description: Elixir version to set up
otp-version:
required: true
type: string
description: OTP version to set up
#################################################################
# Everything below this line is optional.
#
# It's designed to make compiling a reasonably standard Elixir
# codebase "just work," though there may be speed gains to be had
# by tweaking these flags.
#################################################################
build-deps:
required: false
type: boolean
default: true
description: True if we should compile dependencies
build-app:
required: false
type: boolean
default: true
description: True if we should compile the application itself
build-flags:
required: false
type: string
default: '--all-warnings'
description: Flags to pass to mix compile
install-rebar:
required: false
type: boolean
default: true
description: By default, we will install Rebar (mix local.rebar --force).
install-hex:
required: false
type: boolean
default: true
description: By default, we will install Hex (mix local.hex --force).
cache-key:
required: false
type: string
default: 'v1'
description: If you need to reset the cache for some reason, you can change this key.
outputs:
otp-version:
description: "Exact OTP version selected by the BEAM setup step"
value: ${{ steps.beam.outputs.otp-version }}
elixir-version:
description: "Exact Elixir version selected by the BEAM setup step"
value: ${{ steps.beam.outputs.elixir-version }}
runs:
using: "composite"
steps:
- name: Setup elixir
uses: erlef/setup-beam@v1.15.4
id: beam
with:
elixir-version: ${{ inputs.elixir-version }}
otp-version: ${{ inputs.otp-version }}

- name: Get deps cache
uses: actions/cache@v2
with:
path: deps/
key: deps-${{ inputs.cache-key }}-${{ runner.os }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
deps-${{ inputs.cache-key }}-${{ runner.os }}-
- name: Get build cache
uses: actions/cache@v2
id: build-cache
with:
path: _build/${{env.MIX_ENV}}/
key: build-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-${{ env.MIX_ENV }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
build-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-${{ env.MIX_ENV }}-
- name: Get Hex cache
uses: actions/cache@v2
id: hex-cache
with:
path: ~/.hex
key: hex-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
hex-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-
- name: Get Mix cache
uses: actions/cache@v2
id: mix-cache
with:
path: ${{ env.MIX_HOME || '~/.mix' }}
key: mix-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
mix-${{ inputs.cache-key }}-${{ runner.os }}-${{ inputs.otp-version }}-${{ inputs.elixir-version }}-
# In my experience, I have issues with incremental builds maybe 1 in 100
# times that are fixed by doing a full recompile.
# In order to not waste dev time on such trivial issues (while also reaping
# the time savings of incremental builds for *most* day-to-day development),
# I force a full recompile only on builds that we retry.
- name: Clean to rule out incremental build as a source of flakiness
if: github.run_attempt != '1'
run: |
mix deps.clean --all
mix clean
shell: sh

- name: Install Rebar
run: mix local.rebar --force --if-missing
shell: sh
if: inputs.install-rebar == 'true'

- name: Install Hex
run: mix local.hex --force --if-missing
shell: sh
if: inputs.install-hex == 'true'

- name: Install Dependencies
run: mix deps.get
shell: sh

# Normally we'd use `mix deps.compile` here, however that incurs a large
# performance penalty when the dependencies are already fully compiled:
# https://elixirforum.com/t/github-action-cache-elixir-always-recompiles-dependencies-elixir-1-13-3/45994/12
#
# Accoring to Jose Valim at the above link `mix loadpaths` will check and
# compile missing dependencies
- name: Compile Dependencies
run: mix loadpaths
shell: sh
if: inputs.build-deps == 'true'

- name: Compile Application
run: mix compile ${{ inputs.build-flags }}
shell: sh
if: inputs.build-app == 'true'
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: mix
directory: "/"
schedule:
interval: daily
time: "11:00"
open-pull-requests-limit: 10
assignees:
- s3cur3
77 changes: 77 additions & 0 deletions .github/workflows/elixir-build-and-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Elixir Unit Tests

on:
push:
branches:
- main
pull_request:
branches:
- "**"

jobs:
build:
name: Elixir Unit Tests
runs-on: ubuntu-20.04
env:
MIX_ENV: test
strategy:
matrix:
elixir: ["1.10.4", "1.11.4", "1.12.3", "1.13.4", "1.14.4", "1.15.5"]
otp: ["22.3", "23.3.4", "24.3.4", "25.3.2", "26.0.2"]
exclude:
# Elixir 1.10 only supports up to OTP 23
- elixir: "1.10.4"
otp: "26.0.2"
- elixir: "1.10.4"
otp: "25.3.2"
- elixir: "1.10.4"
otp: "24.3.4"
# Elixir 1.11 doesn't support the latest OTP
- elixir: "1.11.4"
otp: "25.3.2"
- elixir: "1.11.4"
otp: "26.0.2"
# Elixir 1.12 doesn't support the latest OTP
- elixir: "1.12.3"
otp: "25.3.2"
- elixir: "1.12.3"
otp: "26.0.2"
# Elixir 1.13 doesn't support the latest OTP
- elixir: "1.13.4"
otp: "26.0.2"
# Elixir 1.14 requires at least OTP 23
- elixir: "1.14.4"
otp: "22.3"
# Elixir 1.15 requires at least OTP 24
- elixir: "1.15.5"
otp: "22.3"
- elixir: "1.15.5"
otp: "23.3.4"

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup Elixir Project
uses: ./.github/actions/elixir-setup
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
build-app: false

- name: Compile with warnings as errors
if: ${{ matrix.elixir != '1.11.4' && matrix.elixir != '1.10.4' }}
run: mix compile --warnings-as-errors

# stream_data config doesn't work on Elixir 1.10, but we can at least compile
- name: Compile
if: ${{ matrix.elixir == '1.10.4' }}
run: mix compile

- name: Run tests with warnings as errors
if: ${{ matrix.elixir != '1.11.4' && matrix.elixir != '1.10.4' }}
run: mix test --warnings-as-errors

- name: Run tests
if: ${{ matrix.elixir == '1.11.4' }}
run: mix test
45 changes: 45 additions & 0 deletions .github/workflows/elixir-quality-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Elixir Quality Checks

on:
push:
branches:
- main
pull_request:
branches:
- "**"

jobs:
quality_checks:
name: Elixir Quality Checks
runs-on: ubuntu-latest
env:
# In MIX_ENV=test, `$ mix xref graph` shows us a whole bunch of
# test stuff that isn't really relevant.
# The other checks don't really care what environment they run in.
MIX_ENV: dev
elixir: "1.15.4"
otp: "26.0.2"

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup Elixir Project
uses: ./.github/actions/elixir-setup
with:
elixir-version: ${{ env.elixir }}
otp-version: ${{ env.otp }}
build-app: false

- name: Check for unused deps
run: mix deps.unlock --check-unused

- name: Check code formatting
run: mix format --check-formatted
# We run all checks here even if others failed so that
# we give devs as much feedback as possible & save some time.
if: always()

- name: Check for compile-time dependencies between modules
run: mix xref graph --label compile-connected --fail-above 0
if: always()
32 changes: 32 additions & 0 deletions .github/workflows/elixir-retired-packages-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Elixir Retired Packages Check

on:
push:
branches:
- main
pull_request:
branches:
- "**"

jobs:
retired_packages:
name: Elixir Retired Packages Check
runs-on: ubuntu-latest
env:
MIX_ENV: dev
elixir: "1.15.4"
otp: "26.0.2"

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup Elixir Project
uses: ./.github/actions/elixir-setup
with:
elixir-version: ${{ env.elixir }}
otp-version: ${{ env.otp }}
build-app: false

- name: Check for retired/abandoned deps
run: mix hex.audit
6 changes: 5 additions & 1 deletion lib/geo/geometry_collection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.GeometryCollection do
Defines the GeometryCollection struct.
"""

@type t :: %Geo.GeometryCollection{geometries: [Geo.geometry()], srid: integer | nil, properties: map}
@type t :: %Geo.GeometryCollection{
geometries: [Geo.geometry()],
srid: integer | nil,
properties: map
}
defstruct geometries: [], srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/line_string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.LineString do
Defines the LineString struct.
"""

@type t :: %Geo.LineString{coordinates: [{number, number}], srid: integer | nil, properties: map}
@type t :: %Geo.LineString{
coordinates: [{number, number}],
srid: integer | nil,
properties: map
}
defstruct coordinates: [], srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/line_stringz.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.LineStringZ do
Defines the LineStringZ struct.
"""

@type t :: %__MODULE__{coordinates: [{number, number, number}], srid: integer | nil, properties: map}
@type t :: %__MODULE__{
coordinates: [{number, number, number}],
srid: integer | nil,
properties: map
}
defstruct coordinates: [], srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/multi_point.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.MultiPoint do
Defines the MultiPoint struct.
"""

@type t :: %Geo.MultiPoint{coordinates: [{number, number}], srid: integer | nil, properties: map}
@type t :: %Geo.MultiPoint{
coordinates: [{number, number}],
srid: integer | nil,
properties: map
}
defstruct coordinates: [], srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/multi_pointz.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.MultiPointZ do
Defines the MultiPointZ struct.
"""

@type t :: %__MODULE__{coordinates: [{number, number, number}], srid: integer | nil, properties: map}
@type t :: %__MODULE__{
coordinates: [{number, number, number}],
srid: integer | nil,
properties: map
}
defstruct coordinates: [], srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/pointm.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.PointM do
Defines the PointM struct.
"""

@type t :: %Geo.PointM{coordinates: {number, number, number}, srid: integer | nil, properties: map}
@type t :: %Geo.PointM{
coordinates: {number, number, number},
srid: integer | nil,
properties: map
}
defstruct coordinates: {0, 0, 0}, srid: nil, properties: %{}
end
6 changes: 5 additions & 1 deletion lib/geo/pointz.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ defmodule Geo.PointZ do
Defines the PointZ struct.
"""

@type t :: %Geo.PointZ{coordinates: {number, number, number}, srid: integer | nil, properties: map}
@type t :: %Geo.PointZ{
coordinates: {number, number, number},
srid: integer | nil,
properties: map
}
defstruct coordinates: {0, 0, 0}, srid: nil, properties: %{}
end
Loading

0 comments on commit 219e76d

Please sign in to comment.