-
-
Notifications
You must be signed in to change notification settings - Fork 0
160 lines (147 loc) · 5.5 KB
/
Copy pathelixir-ci-reusable.yml
File metadata and controls
160 lines (147 loc) · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# SPDX-License-Identifier: MPL-2.0
# elixir-ci-reusable.yml — Reusable Elixir CI bundle (RSR).
#
# Replaces the per-repo `elixir-ci.yml` template that copy-drifted (and
# in several cases got corrupted) across the estate. Estate audit
# (2026-05-26) found 9 repos shipping their own copy, with 9 unique
# SHAs — 100% drift. One copy (`bofig`) was YAML-broken with literal
# `npermissions:` lines from a botched permissions injection.
#
# Recurring failure modes observed across the estate:
#
# * Elixir version pinned to 1.15 while mix.exs declared ~> 1.17,
# producing `(Mix) … but it has declared in its mix.exs file
# it supports only Elixir ~> 1.17` (tma-mark2 #41 lived this).
# * `mix compile --warnings-as-errors` applied to the whole
# build, so transitive-dep warnings (e.g. rustler's
# `:json.decode` reference needing Elixir 1.18) failed CI even
# when the project's own code was clean.
# * Inconsistent `permissions:` placement (some at top, some
# mid-file, some missing).
#
# This reusable:
# * Pins to the tma-mark2 #41-validated canonical shape.
# * Compiles deps WITHOUT --warnings-as-errors first, then app code
# with the strict flag — so deps warnings don't fail us but our
# own code still gets the hygiene gate.
# * Gates dialyzer behind an opt-in input (~5-minute cold-cache run
# on most repos).
# * Guards every job on `mix.exs` presence so consumers can add
# the wrapper unconditionally.
#
# Caller example:
#
# jobs:
# elixir-ci:
# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613
#
# With dialyzer + customised versions:
#
# jobs:
# elixir-ci:
# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613
# with:
# elixir-version: "1.18"
# enable_dialyzer: true
#
# Sub-directory project (mix.exs lives in a subfolder — applies to
# burble's server/, feedback-o-tron, verisimdb):
#
# jobs:
# elixir-ci:
# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613
# with:
# working_directory: server
name: Elixir CI (reusable)
on:
workflow_call:
inputs:
runs-on:
description: Runner label for the Elixir CI job
type: string
required: false
default: ubuntu-latest
otp-version:
description: OTP version selector for erlef/setup-beam
type: string
required: false
default: "26"
elixir-version:
description: Elixir version selector for erlef/setup-beam
type: string
required: false
default: "1.17"
enable_dialyzer:
description: Run `mix dialyzer` (slow cold-cache; off by default)
type: boolean
required: false
default: false
enable_credo:
description: Run `mix credo --strict`
type: boolean
required: false
default: true
working_directory:
description: |
Directory containing `mix.exs` (relative to the repo root). All
mix invocations and cache lookups consult this directory.
Default `.` keeps single-app repos unchanged. Set to e.g.
`server` for a sub-app layout (burble, feedback-o-tron,
verisimdb at audit time).
type: string
required: false
default: "."
permissions:
contents: read
jobs:
test:
name: Compile + test
runs-on: ${{ inputs.runs-on }}
# Guard on mix.exs so the wrapper is safe to add unconditionally.
if: ${{ hashFiles(format('{0}/mix.exs', inputs.working_directory)) != '' }}
permissions:
contents: read
env:
MIX_ENV: test
defaults:
run:
working-directory: ${{ inputs.working_directory }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: ${{ github.repository }}
ref: ${{ github.ref }}
- name: Set up BEAM (OTP + Elixir)
uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0
with:
otp-version: ${{ inputs.otp-version }}
elixir-version: ${{ inputs.elixir-version }}
- name: Cache deps
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ inputs.working_directory }}/deps
key: deps-${{ inputs.elixir-version }}-${{ hashFiles(format('{0}/mix.lock', inputs.working_directory)) }}
- name: Cache _build
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ inputs.working_directory }}/_build
key: build-${{ inputs.elixir-version }}-${{ hashFiles(format('{0}/mix.lock', inputs.working_directory)) }}
- name: Install deps
run: mix deps.get
# Compile deps WITHOUT --warnings-as-errors so upstream warnings
# (rustler's :json.decode needing Elixir 1.18, deprecated
# `use Bitwise`, etc.) don't fail the build. Strict mode then
# applies only to the project's own modules in the next step.
- name: Compile dependencies
run: mix deps.compile
- name: Compile project (strict)
run: mix compile --warnings-as-errors
- name: Credo lint
if: ${{ inputs.enable_credo }}
run: mix credo --strict
- name: Dialyzer
if: ${{ inputs.enable_dialyzer }}
run: mix dialyzer
- name: Run tests
run: mix test --cover