local elixir = 'docker.io/library/elixir:1.18.3-otp-27'; local postgres_image = 'docker.io/library/postgres:18.3'; local pg_service = { name: 'postgres', image: postgres_image, environment: { POSTGRES_USER: 'postgres', POSTGRES_PASSWORD: 'postgres', }, }; local cache_volume = { name: 'cache', host: { path: '/tmp/drone_cache' } }; local cache_mount = [{ name: 'cache', path: '/cache' }]; local step_compute_cache = { name: 'compute cache key', image: elixir, commands: [ "mix_lock_hash=$(sha256sum mix.lock | cut -d ' ' -f 1)", 'echo "$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$mix_lock_hash" >> .cache_key', // Print cache key for debugging 'cat .cache_key', ], }; local step_restore_cache = { name: 'restore-cache', image: 'drillster/drone-volume-cache', settings: { restore: true, mount: ['./deps', './_build', './priv/plts'], ttl: 30 }, volumes: cache_mount, }; local step_lint = { name: 'lint', image: elixir, commands: [ 'mix local.hex --force', // Install hex package manager 'mix deps.get', // Fetch dependencies 'mix compile --warnings-as-errors', // Check for compilation errors & warnings 'mix format --check-formatted', // Check formatting 'mix sobelow --config', // Security checks 'mix deps.audit --ignore-file .deps_audit_ignore', // Known vulnerabilities 'mix hex.audit', // Unmaintained dependencies 'mix credo --strict', // Code quality hints 'mix gettext.extract --check-up-to-date', // Translations up to date ], }; local step_typecheck = { name: 'typecheck', image: elixir, commands: [ 'mix local.hex --force', 'mix deps.get', 'mkdir -p priv/plts', // Build/refresh PLT — no-op on cache hit, full build (5-15 min) on cache miss. 'mix dialyzer --plt', // Actual typecheck. --format short keeps log noise down on red builds. 'mix dialyzer --format short', ], }; local step_wait_postgres = { name: 'wait_for_postgres', image: postgres_image, commands: [ ||| for i in {1..20}; do if pg_isready -h postgres -U postgres; then exit 0 else true fi sleep 2 done echo "Postgres did not become available, aborting." exit 1 |||, ], }; local step_rebuild_cache = { name: 'rebuild-cache', image: 'drillster/drone-volume-cache', settings: { rebuild: true, mount: ['./deps', './_build', './priv/plts'] }, volumes: cache_mount, }; // test_cmd is the only thing that differs between the fast and full suites. local test_step(name, test_cmd) = { name: name, image: elixir, environment: { MIX_ENV: 'test', TEST_POSTGRES_HOST: 'postgres', TEST_POSTGRES_PORT: '5432', }, commands: ['mix local.hex --force', 'mix deps.get', test_cmd], }; local test_fast = test_step('test-fast', 'mix test --exclude slow --exclude ui --max-cases 2'); local test_all = test_step('test-all', 'mix test'); // A full check pipeline: identical steps, only name + trigger + test step vary. local check_pipeline(name, trigger, test) = { kind: 'pipeline', type: 'docker', name: name, services: [pg_service], trigger: trigger, steps: [ step_compute_cache, step_restore_cache, step_lint, ] + (if test.name == 'test-all' then [step_typecheck] else []) + [ step_wait_postgres, test, step_rebuild_cache, ], volumes: [cache_volume], }; local docker_publish(name, extra_settings, trigger_event, deps) = { kind: 'pipeline', type: 'docker', name: name, trigger: trigger_event, steps: [{ name: 'build-and-publish-container' + (if name == 'build-and-publish' then '-branch' else ''), image: 'plugins/docker', settings: { registry: 'git.local-it.org', repo: 'git.local-it.org/local-it/mitgliederverwaltung', username: { from_secret: 'DRONE_REGISTRY_USERNAME' }, password: { from_secret: 'DRONE_REGISTRY_TOKEN' }, } + extra_settings, when: trigger_event, }], depends_on: deps, }; [ check_pipeline('check-fast', { branch: { exclude: ['main'] }, event: ['push'] }, test_fast), check_pipeline('check-full', { branch: ['main'], event: ['push'] }, test_all), check_pipeline('check-full-promote', { event: ['promote'], target: ['production'] }, test_all), check_pipeline('check-full-tag', { event: ['tag'] }, test_all), docker_publish( 'build-and-publish', { tags: ['latest', '${DRONE_COMMIT_SHA:0:8}'] }, { branch: ['main'], event: ['push'] }, ['check-full'], ), docker_publish( 'build-and-release', { auto_tag: true }, { event: ['tag'] }, ['check-full-tag'], ), { kind: 'pipeline', type: 'docker', name: 'renovate', trigger: { event: ['cron', 'custom'], branch: ['main'] }, environment: { LOG_LEVEL: 'debug' }, steps: [{ name: 'renovate', image: 'renovate/renovate:43.165', environment: { RENOVATE_CONFIG_FILE: 'renovate_backend_config.js', RENOVATE_TOKEN: { from_secret: 'RENOVATE_TOKEN' }, GITHUB_COM_TOKEN: { from_secret: 'GITHUB_COM_TOKEN' }, }, commands: [ // https://github.com/renovatebot/renovate/discussions/15049 'unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL', 'renovate-config-validator', 'renovate', ], }], }, ]