Tool for sharing tooling configuration between Elixir repos. Detects drift from a baseline configuration and opens pull requests to fix it, and reports the GitHub settings and the unenrolled projects a pull request cannot fix.
Owned by the tool and rendered from a template. When the template is changed, the file in the repository is overwritten as a whole.
The default templates include:
.credo.exsrenovate.jsonSECURITY.md(only generated for public repositories).github/CODEOWNERS.github/workflows/hadolint.yaml(only generated for repositories with aDockerfile).github/workflows/llm-attribution.yaml.github/workflows/zizmor.yaml
Pinned hashes in Github Actions workflows are not overwritten from templates.
Owned in parts and patched when settings are changed.
Currently supported:
line_lengthin.formatter.exs(also applied in the default.credo.exstemplate)
GitHub settings are read through the API and only reported.
Currently supported checks:
SECURITY.mdexists in either the repo or inherited from the owner's.githubrepo (only public repositories).- Private vulnerability reporting is enabled (only public repositories).
- No Actions secret is held at the repository level (only public repositories). Every job in a repository can read a repository secret. In a public repository any workflow change that gets merged runs with it. A secret belongs in an environment, which gates it behind the reviewers that environment requires. Only secret names are read, never values.
The drift check only looks at the paths the configuration expects, so a Mix
project that is not listed under projects is invisible to it and its
repository reads as fully covered.
The unclaimed check searches the other way. It goes over every path in the
repository and reports a mix.exs, or a file one of the project templates
generates, sitting in a directory that no configured project claims. That
catches a project dropped from the configuration by mistake, and a nested
application that was added to a repository but never enrolled.
An unclaimed file is fixed in the configuration rather than by a pull request, so it is counted separately.
You need the gh CLI installed and authenticated.
To use this tool, you need to clone it and create a configuration file.
git clone https://github.com/woylie/elixir_baseline.git
cd elixir_baseline
cp .baseline.exs .baseline.override.exs.baseline.exs is the default configuration I use for my own repositories. With
the commands above, it is copied to .baseline.override.exs, which you can
edit for your own repositories.
If .baseline.override.exs exists, the Mix tasks will use it as a default.
Otherwise, they fall back to .baseline.exs. You can also pass a different path
with the --config argument. Configuration files named .baseline.*.exs are
gitignored in this repository.
.baseline.exs lists all the repo settings:
[
defaults: [
# The `all` group contains defaults that are applied to all repos.
# You can add any number of additional groups under `defaults`. They are
# referenced with the `group` option under `repos`.
all: [
owner: "woylie",
line_length: 80,
conditions: %{
"repo/.github/workflows/hadolint.yaml" => {:exists, "Dockerfile"}
},
extra: [
security_contacts: ["[Contact form](https://example.com/contact)"]
]
],
library: [
extra: [renovate_presets: ["github>woylie/renovate-presets:library"]]
],
application: [
extra: [renovate_presets: ["github>woylie/renovate-presets:application"]]
]
],
repos: [
doggo: [
group: :library,
projects: [doggo: [path: "."], demo: [group: :application]]
],
spek: [group: :library]
]
]The lookup order of the repo settings is:
- configuration under
projects - configuration under
repos - group configuration under
defaults - "all" group configuration
- elixir_baseline's own defaults
mix baseline.check # report which files and settings have drifted
mix baseline.check --repo spek
mix baseline.pr # open a pull request per drifted repo
mix baseline.pr --repo spek
mix baseline.pr --dry-run # what would change, writing nothing
mix baseline.pr --dry-run --diff
mix baseline.pr --interactive # confirm each file before it is written
Both tasks take --repo, which may be given more than once, and --config for
a config file elsewhere.
check reads each repo's default branch through the API without cloning the
repositories.
pr runs the check first and only clones the repos that need it. Each one is
cloned shallowly into a temporary directory. Re-running is safe.
$ mix baseline.check
woylie/ecto_nested_changeset
.github/workflows/zizmor.yaml missing
SECURITY.md missing
woylie/elixir_baseline
SECURITY.md missing
woylie/ex_icon
SECURITY.md missing
woylie/flop
.github/workflows/zizmor.yaml missing
SECURITY.md missing
woylie/let_me
.github/workflows/zizmor.yaml missing
SECURITY.md missing
woylie/spek
SECURITY.md missing
private vulnerability reporting disabled
run: gh api --method PUT repos/woylie/spek/private-vulnerability-reporting
43/52 files match the baseline.
15/16 settings match the baseline.
Run mix baseline.pr to update the files.
** (Mix) 9 file(s) and 1 setting(s) drifted from the baseline
$ mix baseline.pr
doggo: unchanged
ecto_nested_changeset: cloning... pushing... https://github.com/woylie/ecto_nested_changeset/pull/457
elixir_baseline: cloning... pushing... https://github.com/woylie/elixir_baseline/pull/12
ex_icon: cloning... pushing... https://github.com/woylie/ex_icon/pull/28
flop: cloning... pushing... https://github.com/woylie/flop/pull/717
flop_phoenix: unchanged
let_me: cloning... pushing... https://github.com/woylie/let_me/pull/213
spek: cloning... pushing... https://github.com/woylie/spek/pull/71
The templates are in the priv/templates folder, split into repo and
project. To use your own templates instead, list the directories under
templates. :default in that list stands for the templates that ship with
this tool.
A template is referenced by its full relative path in the template folder,
without the .eex. include and exclude options are supported. You can also
set conditions that must be met for a template to be generated:
conditions: %{
"repo/.github/workflows/hadolint.yaml" => {:exists, "Dockerfile"}
}The path in a condition is relative to the repository root.
seed lists the templates that are written once and then belong to the project:
seed: ["project/.sobelow-conf"]A seeded template is written if the file is missing and left alone if it is present. Every other template is owned: compared, and overwritten if it differs.