Files
firezone/.github/workflows/_elixir.yml
Jamil 6575e0ca26 chore(ci): Refactor CI to use prod images in staging and prevent accidental hotfix breakages (#4049)
- Runs release asset builds simultaneously with `deploy-staging`. Those
don't depend on each other.
- Prevents running some build workflows in CD because they're run
already in the PR and in the merge group, and the risk of semantic
conflict is negligible
- Run `release` assets in staging
- Adds `compatibility_tests`: **To successfully introduce a breaking
change in the control / data plane APIs, you must now "Merge as
Administrator"**
- Since `CI` is no longer run on `main`, caching needed to be refactored
to make sense again
- Since `CI` is no longer run on `main`, the Elixir
`migrations_and_seeds_test` had to be rewritten. This now tests
migrations using `git checkout` instead of importing `main`'s DB dump.
- Move tauri builds to its own workflow so we can trigger Linux and
Windows builds manually on an adhoc basis like we do for the Swift and
Kotlin builds
- Add a new `hotfix` workflow that will run `compatibility_tests` with
the latest published images
- Add `workflow_dispatch` to trigger `CD` manually for testing purposes
(cc @ReactorScram)


Refs #3995
2024-03-11 20:01:34 +00:00

467 lines
17 KiB
YAML

name: Elixir
on:
workflow_call:
jobs:
unit-test:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./elixir
permissions:
checks: write
env:
MIX_ENV: test
POSTGRES_HOST: localhost
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
services:
postgres:
image: postgres:15.2
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Tool Versions
id: versions
uses: marocchino/tool-versions-action@v1.2.0
- uses: erlef/setup-beam@v1
id: setup-beam
with:
otp-version: ${{ steps.versions.outputs.erlang }}
elixir-version: ${{ steps.versions.outputs.elixir }}
- uses: actions/cache/restore@v4
name: Restore Elixir Deps Cache
id: cache
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Install Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.get --only $MIX_ENV
- name: Compile Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.compile --skip-umbrella-children
- uses: actions/cache/save@v4
name: Save Elixir Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Compile Application
run: mix compile --warnings-as-errors
- name: Setup Database
run: |
mix ecto.create
mix ecto.migrate
- name: Run Tests
env:
E2E_DEFAULT_WAIT_SECONDS: 20
run: |
mix test --warnings-as-errors
- name: Test Report
uses: dorny/test-reporter@v1
if:
${{ github.event.pull_request.head.repo.full_name == github.repository
&& (success() || failure()) }}
with:
name: Elixir Unit Test Report
path: elixir/_build/test/lib/*/test-junit-report.xml
reporter: java-junit
type-check:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./elixir
env:
# We need to set MIX_ENV to dev to make sure that we won't type-check our test helpers
MIX_ENV: dev
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Tool Versions
id: versions
uses: marocchino/tool-versions-action@v1.2.0
- uses: erlef/setup-beam@v1
id: setup-beam
with:
otp-version: ${{ steps.versions.outputs.erlang }}
elixir-version: ${{ steps.versions.outputs.elixir }}
- uses: actions/cache/restore@v4
name: Restore Elixir Deps Cache
id: cache
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Install Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.get --only $MIX_ENV
- name: Compile Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.compile --skip-umbrella-children
- uses: actions/cache/save@v4
name: Save Elixir Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Compile Application
run: mix compile --warnings-as-errors
- uses: actions/cache/restore@v4
name: Restore PLT cache
id: plt_cache
with:
path: elixir/priv/plts
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ hashFiles('elixir/mix.lock') }}
# This will make sure that we can incrementally build the PLT from older cache and save it under a new key
restore-keys: |
ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-
- name: Create PLTs
if: ${{ steps.plt_cache.outputs.cache-hit != 'true' }}
run: mix dialyzer --plt
- uses: actions/cache/save@v4
if: ${{ github.ref_name == 'main' }}
name: Save PLT cache
with:
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ hashFiles('elixir/mix.lock') }}
path: elixir/priv/plts
- name: Run Dialyzer
run: mix dialyzer --format dialyxir
static-analysis:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./elixir
env:
MIX_ENV: test
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Tool Versions
id: versions
uses: marocchino/tool-versions-action@v1.2.0
- uses: erlef/setup-beam@v1
id: setup-beam
with:
otp-version: ${{ steps.versions.outputs.erlang }}
elixir-version: ${{ steps.versions.outputs.elixir }}
- uses: actions/cache/restore@v4
name: Restore Elixir Deps Cache
id: cache
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Install Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.get --only $MIX_ENV
- name: Compile Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.compile --skip-umbrella-children
- uses: actions/cache/save@v4
name: Save Elixir Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Compile Application
run: mix compile --force --warnings-as-errors
- name: Check Formatting
run: mix format --check-formatted
- name: Check For Retired Packages
run: mix hex.audit
- name: Check For Vulnerable Packages
run: mix deps.audit
- name: Run Sobelow vulnerability scanner for web app
working-directory: ./elixir/apps/web
run: mix sobelow --skip
- name: Run Credo
run: mix credo --strict
- name: Check for unused deps
run: mix deps.unlock --check-unused
migrations-and-seed-test:
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./elixir
env:
MIX_ENV: dev
POSTGRES_HOST: localhost
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
services:
postgres:
image: postgres:15.2
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Install package dependencies
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/pgdg.asc &>/dev/null
sudo apt update
sudo apt-get install -q -y postgresql-client
- name: Tool Versions
id: versions
uses: marocchino/tool-versions-action@v1.2.0
- uses: erlef/setup-beam@v1
id: setup-beam
with:
otp-version: ${{ steps.versions.outputs.erlang }}
elixir-version: ${{ steps.versions.outputs.elixir }}
- uses: actions/cache/restore@v4
name: Restore Elixir Deps Cache
id: cache
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Install Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.get --only $MIX_ENV
- name: Compile Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.compile --skip-umbrella-children
- uses: actions/cache/save@v4
name: Save Elixir Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Compile
run: mix compile --warnings-as-errors
- name: Create Database
run: mix ecto.create
- name: Migrate DB to base ref and seed
run: |
git fetch --depth=1 origin ${{ github.base_ref }}
git checkout ${{ github.base_ref }}
mix ecto.migrate
mix ecto.seed
# Then checkout current ref and rerun migrations
- name: Run new migrations
run: |
git checkout ${{ github.sha }}
mix ecto.migrate
mix ecto.reset
mix ecto.migrate
mix ecto.seed
acceptance-test:
name: acceptance-test-${{ matrix.MIX_TEST_PARTITION }}
permissions:
checks: write
runs-on: ubuntu-22.04
defaults:
run:
working-directory: ./elixir
env:
MIX_ENV: test
POSTGRES_HOST: localhost
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MIX_TEST_PARTITIONS: 1
strategy:
fail-fast: false
matrix:
MIX_TEST_PARTITION: [1]
services:
postgres:
image: postgres:15.2
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s
--health-retries 5
vault:
image: vault:1.12.2
env:
VAULT_ADDR: "http://127.0.0.1:8200"
VAULT_DEV_ROOT_TOKEN_ID: "firezone"
ports:
- 8200:8200/tcp
options: --cap-add=IPC_LOCK
steps:
- uses: actions/checkout@v4
- uses: nanasess/setup-chromedriver@v2
- run: |
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
- name: Tool Versions
id: versions
uses: marocchino/tool-versions-action@v1.2.0
- uses: erlef/setup-beam@v1
id: setup-beam
with:
otp-version: ${{ steps.versions.outputs.erlang }}
elixir-version: ${{ steps.versions.outputs.elixir }}
- uses: ./.github/actions/setup-node
with:
node-version: ${{ steps.versions.outputs.nodejs }}
# Elixir cache
- uses: actions/cache/restore@v4
name: Restore Elixir Deps Cache
id: cache
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Install Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.get --only $MIX_ENV
- name: Compile Dependencies
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
run: mix deps.compile --skip-umbrella-children
- uses: actions/cache/save@v4
name: Save Elixir Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: elixir-deps-${{ env.MIX_ENV }}
with:
path: |
elixir/deps
elixir/_build/${{ env.MIX_ENV }}
key: ubuntu-22.04-${{ runner.arch }}-${{ steps.setup-beam.outputs.elixir-version }}-${{ env.cache-name }}-${{ hashFiles('elixir/mix.lock') }}
- name: Compile Application
run: mix compile --warnings-as-errors
# Front-End deps cache
- uses: actions/cache/restore@v4
name: pnpm Web Deps Cache
id: pnpm-web-deps-cache
env:
cache-name: pnpm-deps-web
with:
path: |
elixir/apps/web/assets/node_modules
elixir/esbuild-*
elixir/tailwind-*
key: ubuntu-22.04-${{ runner.arch }}-${{ env.cache-name }}-${{ hashFiles('elixir/apps/web/assets/pnpm-lock.yaml') }}
- name: Install Front-End Dependencies
if: ${{ steps.pnpm-web-deps-cache.outputs.cache-hit != 'true' }}
run: |
cd apps/web
mix assets.setup
- uses: actions/cache/save@v4
name: Save pnpm Deps Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: pnpm-deps-web
with:
path: |
elixir/apps/web/assets/node_modules
elixir/esbuild-*
elixir/tailwind-*
key: ubuntu-22.04-${{ runner.arch }}-${{ env.cache-name }}-${{ hashFiles('elixir/apps/web/assets/pnpm-lock.yaml') }}
# Front-End build cache, it rarely changes so we cache it aggressively too
- uses: actions/cache/restore@v4
name: Web Assets Cache
id: pnpm-web-build-cache
env:
cache-name: pnpm-build-web
with:
path: |
elixir/apps/web/assets/tmp
elixir/apps/web/priv/static
key: ubuntu-22.04-${{ runner.arch }}-${{ env.cache-name }}-${{ hashFiles('elixir/apps/web/assets/**') }}
- name: Build Web Assets
if: ${{ steps.pnpm-web-build-cache.outputs.cache-hit != 'true' }}
run: |
cd apps/web
mix assets.build
- uses: actions/cache/save@v4
name: Save Web Assets Cache
if: ${{ github.ref_name == 'main' }}
env:
cache-name: pnpm-build-web
with:
path: |
elixir/apps/web/assets/tmp
elixir/apps/web/priv/static
key: ubuntu-22.04-${{ runner.arch }}-${{ env.cache-name }}-${{ hashFiles('elixir/apps/web/assets/**') }}
# Run tests
- name: Setup Database
run: |
mix ecto.create
mix ecto.migrate
- name: Run Acceptance Tests
env:
MIX_TEST_PARTITION: ${{ matrix.MIX_TEST_PARTITION }}
E2E_DEFAULT_WAIT_SECONDS: 5
run: |
mix test --only acceptance:true \
--partitions=${{ env.MIX_TEST_PARTITIONS }} \
--no-compile \
--no-archives-check \
--no-deps-check \
|| pkill -f chromedriver \
|| mix test --only acceptance:true --failed \
|| pkill -f chromedriver \
|| mix test --only acceptance:true --failed
- name: Save Screenshots
if:
${{ github.event.pull_request.head.repo.full_name == github.repository
&& always() }}
uses: actions/upload-artifact@v4
with:
name: screenshots-${{ matrix.MIX_TEST_PARTITION }}
path: elixir/apps/web/screenshots
- name: Test Report
uses: dorny/test-reporter@v1
if:
${{ github.event.pull_request.head.repo.full_name == github.repository
&& (success() || failure()) }}
with:
name: Elixir Acceptance Test Report
path: elixir/_build/test/lib/*/test-junit-report.xml
reporter: java-junit