agru replaces an installed role whenever its version differs from the
pinned one, and also when the role has no install information. It
replaces a symlinked role with a fresh copy. ansible-galaxy was run on
an emptied roles/galaxy every time. Roles being worked on in
roles/galaxy could thus silently lose their changes.
bin/install-roles.py (run through bin/ansible-python.sh, so PyYAML
needs no separate installation) now decides which roles need to be
(re)installed and only passes those to agru or ansible-galaxy:
- missing roles are installed, and outdated roles are replaced
- outdated roles which were changed since they were installed are kept,
with a warning. Changes are detected by comparing the role's contents
with a checksum recorded at installation, in run/installed-roles.yml.
Roles installed before (without a checksum) are considered unchanged.
- outdated roles which were not installed by agru or ansible-galaxy
are kept, with a warning
- symlinked roles and roles containing a `.git` directory are never
touched
`just roles --force` replaces changed roles too. `just update -u` now
only updates the pinned versions with agru and leaves installing the
roles to the script, so that it keeps changed roles as well.
The same script in mash-playbook (where its tests live, and where it
also deletes the roles of services no longer in use):
https://github.com/mother-of-all-self-hosting/mash-playbook/commit/d5c5e0cehttps://github.com/mother-of-all-self-hosting/mash-playbook/commit/608a7943
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`just update` pulled the playbook first and only then looked at its
flags. An unknown flag printed a message and was then passed to agru
anyway, and `-u` without agru was silently ignored.
Both now stop `just update` with an error, before anything is pulled.
The same change in mash-playbook:
https://github.com/mother-of-all-self-hosting/mash-playbook/commit/0598aa82
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`just update` had its own copy of the agru and ansible-galaxy calls.
It now installs roles through `_install-roles`, like `just roles`.
With `-u` (and agru), it still updates the role versions pinned in
requirements.yml, which also installs them.
The same change in mash-playbook (which additionally regenerates its
optimized files there):
https://github.com/mother-of-all-self-hosting/mash-playbook/commit/32db6a41
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`just roles` and `just update` each had their own copy of the agru and
ansible-galaxy calls. Move them to a private `_install-roles` recipe,
used by `just roles` for now, so that `just update` can use it too.
The same change in mash-playbook:
https://github.com/mother-of-all-self-hosting/mash-playbook/commit/6433a355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* set inventory from $ANSIBLE_INVENTORY if set, otherwise set the default
* Use env() instead of the deprecated env_var_or_default() in justfile
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Slavi Pantaleev <slavi@devture.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`just molecule` leaves a shared virtualenv of over 500 MB under var/, plus a
~7 MB Ansible home per role that has a scenario. Neither is reclaimed by
anything today.
`--idle-days N` limits it to what has not been touched recently, so it can be
run unattended without taking the cache out from under a scenario being worked
on right now.
The two directories are named explicitly rather than globbed: var/ holds other
things and must never be removed wholesale.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
Three things that would not have scaled to 70 roles:
- The Python and Ansible dependency pins were about to be copied into every
role. They now live once in molecule-shared/, which scenarios reference
relatively, so they cannot drift apart.
- The helper container images used for probing were hardcoded inline. They
are pinned once in molecule-shared/vars.yml, carry `# renovate:`
annotations, and a custom manager in .github/renovate.json keeps them
current - verified with a local Renovate dry run, which offers
curl 8.11.1 -> 8.21.0 and python 3.13 -> 3.14-alpine. Seventy invisible
hardcodes is the blindness class we have been removing elsewhere.
- Running a scenario meant knowing the venv and cd incantation. `just
molecule <role>` does it, and with no argument lists the roles that have
a scenario.
Molecule is deliberately not wired into prek: a run takes minutes, pulls
images and needs Docker, which is fine on request and not fine per commit.
docs/molecule-testing.md covers how to run and write these, including the
four things a role here needs that a standalone role does not. AGENTS.md
points at it rather than carrying the detail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
prek bakes the full path of the currently installed version into the hooks it
generates (var/mise/installs/prek/<version>/...). That path stops existing as
soon as the pinned version changes or old versions are pruned, and the hook's
PATH fallback finds no prek either, so every commit fails until the hook is
regenerated by hand. It also means a hook keeps running the version it was
generated with, long after mise.toml has moved on.
Rewriting PREK to mise's shim makes the hook resolve whatever mise.toml pins at
the time it runs. The accompanying MISE_DATA_DIR / MISE_TRUSTED_CONFIG_PATHS
exports keep that resolution inside this project - without them mise falls back
to the global data directory and silently installs a second copy of the tool.
The patch loop now covers every hook file prek generated rather than just
pre-commit, since default_install_hook_types decides which ones exist.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Since mautrix-meta v26.07, Instagram is a separate bridge upstream (its own binary, container image and configuration schema). As of v0.2608.0, the bridge no longer has a `mode` configuration option at all, so the premise of auto-generating the Instagram role from the Messenger one (one binary, one schema, a mode switch) is gone.
- Drop the role generator (`bin/rebuild-mautrix-meta-instagram.sh` and the `just rebuild-mautrix-meta-instagram` recipe). The two roles are now maintained independently.
- Drop `matrix_bridge_mautrix_meta_instagram_meta_mode` and all mode-derived lookups from the Instagram role. Computed values are unchanged.
- Sync both config templates with the v0.2608.0 example configs: the Instagram template loses `mode` and gains the Instagram-only options; the Messenger template replaces `mode` with the new `tor` option (still derived from `matrix_bridge_mautrix_meta_messenger_meta_mode: facebook-tor`) and loses the Instagram-only `disable_xma_*` options.
- Fix self-building for the Instagram role: build via `Dockerfile.ig` (producing the actual Instagram binary at `/usr/bin/mautrix-instagram`) instead of the Messenger `Dockerfile`. A new `matrix_bridge_mautrix_meta_instagram_container_binary_path` variable points the systemd service at the right binary for self-built and prebuilt images.
- Rename the systemd service templates to role-specific file names.
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5510
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Running `just add-inventory-host example.com 1.2.3.4` (or
`make add-inventory-host domain=example.com ip=1.2.3.4`) adds a new
host to the inventory, creating inventory/hosts and
inventory/host_vars/matrix.DOMAIN/vars.yml from the example files,
with strong secrets generated automatically.
Existing configuration is never overwritten. The command refuses to
run if the host is already in the inventory, so it can also be used
for adding more hosts later.
Based on the idea proposed in
https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/4682 by @Ser5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Override devture_systemd_service_manager_conditional_restart_enabled in
group_vars based on ansible_run_tags: disabled when setup-* tags are used,
enabled otherwise. This replaces the --extra-vars hack in the justfile and
ensures consistent behavior for both `just` and raw `ansible-playbook` users.
- Revert justfile setup-all to its original form (no --extra-vars needed).
- Update docs/just.md to reflect tag-agnostic behavior.
- Add CHANGELOG.md entry documenting the conditional restart feature.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Traefik's service list entry now uses the `traefik_restart_necessary`
variable (computed by the Traefik role) instead of hardcoded `true`,
so it is only restarted when its config, systemd unit, or image changed.
- `just setup-all` now passes
`devture_systemd_service_manager_conditional_restart_enabled=false`
to force unconditional restarts, matching its "full setup" semantics.
- Document the conditional restart behavior in docs/just.md.
Some benchmarks follow for `just install-service traefik -l matrix.example.com`
when Traefik settings did not change and a restart is not really necessary:
- Before:
- total time: 56 seconds 🐌
- Traefik restarted: yes ❌
- Services that depend on Traefik restarted: yes; all of them restarted ❌
- After:
- total time: 27 seconds ⚡
- Traefik restarted: no ✅
- Services that depend on Traefik restarted: no; none restarted ✅
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* rewrite `just update` command to provide a one-line command to update everything
* update prefix
* uncomment update-self
* Revert requirements.yml updates not belonging to this PR
* Justfile and documentation updates to make things clearer
---------
Co-authored-by: Slavi Pantaleev <slavi@devture.com>
It should be noted that this cannot be used for the initial install
of services which require a database or have other dependencies.
Those would typically need to invoke the playbook with
`--tags=install-postgres,install-SERVICE`, etc.
The purpose of this shortcut is to easily rebuild and restart
a single serice subsequently. For those cases, often times there's no need to
reinitialize the database and other components and simply running a
single component's tasks is enough.