Skip to content
276 changes: 195 additions & 81 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@ version: 2.1
orbs:
codecov: codecov/codecov@1.0.5

# Shared configuration
defaults:
elixir_version: &elixir_version "1.18.3-otp-27"
nodejs_version: &nodejs_version "22.12.0"
docker_elixir: &docker_elixir
- image: elixir:1.18.3-otp-27
docker_elixir_postgres: &docker_elixir_postgres
- image: elixir:1.18.3-otp-27
- image: cimg/postgres:17.3
environment: &environment
ERL_FLAGS: +S 4:4
ASSERT_RECEIVE_TIMEOUT: 1000
MIX_ENV: test

executors:
elixir:
docker: *docker_elixir
environment: *environment
working_directory: /home/lightning/project

elixir_with_postgres:
docker: *docker_elixir_postgres
environment: *environment
working_directory: /home/lightning/project

commands:
install_node:
description: "Install NodeJS from NodeSource"
Expand All @@ -17,121 +42,210 @@ commands:
curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash -
apt-get install -y nodejs=<< parameters.version >>-1nodesource1

jobs:
build:
parameters:
elixir_version:
description: Elixir version
type: string
default: "1.18.3-otp-27"
nodejs_version:
description: NodeJS version
type: string
default: "22.12.0"
execute:
description: What steps to execute after build
type: steps

parallelism: 1
docker:
- image: elixir:<< parameters.elixir_version >>
- image: cimg/postgres:17.3
environment:
ERL_FLAGS: +S 4:4
ASSERT_RECEIVE_TIMEOUT: 1000
MIX_ENV: test
working_directory: /home/lightning/project
setup_lightning_user:
description: "Create lightning user and configure sudo"
steps:
- run:
name: "Create lightning user"
command: adduser --home /home/lightning --system lightning
- run:
name: "Install sudo and configure environment passthrough"
command: |
apt-get update && apt-get install -y sudo
echo 'Defaults env_keep += "ERL_FLAGS ASSERT_RECEIVE_TIMEOUT MIX_ENV"' | \
sudo EDITOR='tee -a' visudo
- run:
name: "Configure git safe directory"
command: git config --global --add safe.directory /home/lightning/project

attach_built_workspace:
description: "Attach workspace and restore ownership"
steps:
- run: adduser --home /home/lightning --system lightning
- attach_workspace:
at: /home/lightning/project
- run:
name: "Restore ownership after workspace attach"
command: chown -R lightning /home/lightning
- run:
name: "Install Hex and Rebar"
command: sudo -u lightning mix local.hex --force && sudo -u lightning mix local.rebar --force

jobs:
# ============================================================================
# COMPILE JOB - Builds everything once, persists to workspace
# ============================================================================
compile:
executor: elixir
steps:
- setup_lightning_user
- checkout
- run:
name: "Set ownership"
command: chown -R lightning /home/lightning
- install_node:
version: << parameters.nodejs_version >>
version: *nodejs_version

- run:
name: "Save Elixir and Erlang version for PLT caching"
name: "Save Elixir and Erlang version for caching"
command: echo "$ELIXIR_VERSION $OTP_VERSION" | tee .elixir_otp_version

- run:
name: "Introspect schedulers"
command: elixir -v

# Restore dependency cache
- restore_cache:
keys:
- v5-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
- v5-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}
- 2026-02-05-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
- 2026-02-05-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}

- run:
name: "Fix ownership after cache restore"
command: chown -R lightning /home/lightning

- run:
name: "Install libsodium and sudo"
name: "Install build dependencies"
command: |
apt-get update && apt-get install -y \
build-essential \
cmake \
libsodium-dev \
sudo
- run: |
echo 'Defaults env_keep += "ERL_FLAGS ASSERT_RECEIVE_TIMEOUT MIX_ENV"' | \
sudo EDITOR='tee -a' visudo

- run: chown -R lightning /home/lightning
- run: sudo -u lightning mix local.hex --force && mix local.rebar --force
- run: cd assets; sudo -u lightning npm install --force
- run: sudo -u lightning mix do deps.get --only test, deps.compile, compile
- run: sudo -u lightning mix lightning.install_runtime
libsodium-dev

- run:
name: "Install Hex and Rebar"
command: sudo -u lightning mix local.hex --force && sudo -u lightning mix local.rebar --force

- run:
name: "Install Node dependencies"
command: cd assets && sudo -u lightning npm install --force

- run:
name: "Compile Elixir dependencies and application"
command: sudo -u lightning mix do deps.get --only test, deps.compile, compile

- run:
name: "Install runtime dependencies"
command: sudo -u lightning mix lightning.install_runtime

- save_cache:
key: v5-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
key: 2026-02-05-deps-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
paths:
- _build
- deps
- ~/.mix
- /home/lightning/.mix

# Restore and build PLT for Dialyzer
- restore_cache:
name: "Restore PLT cache"
keys:
- v5-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
- v5-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}
- 2026-02-05-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
- 2026-02-05-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}

- run:
name: "Ensure PLT directory exists"
command: mkdir -p priv/plts && chown -R lightning priv/plts

- run:
name: "Build Dialyzer PLT"
command: sudo -u lightning env MIX_ENV=test mix dialyzer --plt

- run: mkdir -p priv/plts && chown -R lightning priv/plts
- run: sudo -u lightning env MIX_ENV=test mix dialyzer --plt
- save_cache:
key: v5-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
key: 2026-02-05-plt-{{ arch }}-{{ checksum ".elixir_otp_version" }}-{{ checksum "mix.lock" }}
paths:
- priv/plts

- steps: << parameters.execute >>
# Persist everything to workspace for downstream jobs
- persist_to_workspace:
root: /home/lightning/project
paths:
- .

# ============================================================================
# CHECK JOBS - Fast, parallel jobs that use the pre-built workspace
# ============================================================================
lint:
executor: elixir
steps:
- setup_lightning_user
- attach_built_workspace
- run:
name: "Check code formatting"
command: |
sudo -u lightning mix format --check-formatted || touch /tmp/lint_failed
- run:
name: "Check code style with Credo"
when: always
command: |
sudo -u lightning mix credo --strict --all || touch /tmp/lint_failed
- run:
name: "Check for security vulnerabilities"
when: always
command: |
sudo -u lightning mix sobelow --threshold medium || touch /tmp/lint_failed
- run:
name: "Verify all checks passed"
when: always
command: |
if [ -f /tmp/lint_failed ]; then
echo "One or more lint checks failed"
exit 1
fi

check_dialyzer:
executor: elixir
steps:
- setup_lightning_user
- attach_built_workspace
- run:
name: "Run Dialyzer type checking"
command: sudo -u lightning mix dialyzer

test_elixir:
executor: elixir_with_postgres
steps:
- setup_lightning_user
- attach_built_workspace
- install_node:
version: *nodejs_version
- run:
name: "Install libsodium"
command: apt-get update && apt-get install -y libsodium-dev
- run:
name: "Setup test database"
command: sudo -u lightning mix do ecto.create, ecto.migrate
- run:
name: "Run Elixir tests"
command: sudo -u lightning ./bin/ci_tests
- codecov/upload:
file: test/reports/coverage.json
- store_test_results:
path: test/reports/

test_javascript:
executor: elixir
steps:
- setup_lightning_user
- attach_built_workspace
- install_node:
version: *nodejs_version
- run:
name: "Run JavaScript tests"
command: cd assets && sudo -u lightning npm run test-report
- store_test_results:
path: test/reports/

workflows:
pre-flight checks:
jobs:
- build:
name: "Check code formatting"
execute:
- run: sudo -u lightning mix format --check-formatted
- build:
name: "Check code style"
execute:
- run: sudo -u lightning mix credo --strict --all
- build:
name: "Type check"
execute:
- run: sudo -u lightning mix dialyzer
- build:
name: "Check for security vulnerabilities"
execute:
- run: sudo -u lightning mix sobelow --threshold medium
- build:
name: "Check Elixir tests (codecov)"
execute:
- run: sudo -u lightning mix do ecto.create, ecto.migrate
- run:
command: sudo -u lightning ./bin/ci_tests
- codecov/upload:
file: test/reports/coverage.json
- store_test_results:
path: test/reports/
- build:
name: "Check Javascript tests"
execute:
- run: cd assets; sudo -u lightning npm install && npm run test-report
- store_test_results:
path: test/reports/
# First: compile everything once
- compile

# Then: run all checks in parallel using the compiled workspace
- lint:
requires: [compile]
- check_dialyzer:
requires: [compile]
- test_elixir:
requires: [compile]
- test_javascript:
requires: [compile]
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ lightning-*.tar

# Ignore adaptor registry cache
adaptor_registry_cache.json
!test/fixtures/adaptor_registry_cache.json

# Ignore assets that are produced by build tools.
/priv/static/images/adaptors/
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,20 @@ and this project adheres to

### Changed

- Refactor CircleCI to build-then-fan-out pattern, compiling once then running
checks in parallel to eliminate cache race conditions and reduce flaky tests
[#4378](https://github.com/OpenFn/lightning/pull/4378)

### Fixed

- Version chip missing tooltips
[#4389](https://github.com/OpenFn/lightning/pull/4389)
- Fixed StaleEntryError when saving workflows where a job is replaced and its
edge retargeted to a new job (e.g. via AI assistant)
[#4383](https://github.com/OpenFn/lightning/issues/4383)

## [2.15.13] - 2026-02-06

## [2.15.13-pre1] - 2026-02-05

### Fixed
Expand Down Expand Up @@ -93,6 +105,8 @@ and this project adheres to

- Standardise copy button feedback across collaborative editor
[#3578](https://github.com/OpenFn/lightning/issues/3578)
- Modified version hashing algorithm for CLI compatibility
[#4346](https://github.com/OpenFn/lightning/issues/4346)

### Fixed

Expand Down
Loading