refactor(gateway): migrate Mattermost adapter to bundled plugin (salvage of #30916)#31748
Merged
Conversation
Second migration of an existing built-in platform adapter after Discord (PR #30591) — follows the same shape established by IRC / Teams / LINE / Google Chat / SimpleX and the playbook in `references/platform-plugin-migration.md`. Advances the umbrella refactor in #3823. Matches Discord's parity bar — adapter under `plugins/platforms/mattermost/` with the standard `__init__.py` / `adapter.py` / `plugin.yaml` shell, `register(ctx)` entry point, **no back-compat shim** at the old import path, and full parity for all five hooks Discord uses plus the `apply_yaml_config_fn` hook (mattermost is the second consumer of #25443 after Discord): * `standalone_sender_fn` — out-of-process cron delivery via Mattermost REST API. Picks up the thread_id + media_files capabilities the legacy `_send_mattermost` lacked (parity with Discord's `_standalone_send`). * `setup_fn` — interactive `hermes setup gateway` wizard. * `apply_yaml_config_fn` — translates `config.yaml` `mattermost:` keys (`require_mention`, `free_response_channels`, `allowed_channels`) into `MATTERMOST_*` env vars (replaces the hardcoded block in `gateway/config.py`). * `is_connected` — declares connection state from `MATTERMOST_TOKEN` + `MATTERMOST_URL`. * `check_fn` — verifies aiohttp is installed and both required env vars are set. * plus `allowed_users_env`, `allow_all_env`, `cron_deliver_env_var`, `max_message_length` (4000 — Mattermost practical limit), `emoji`, `required_env`, `install_hint`. Files ----- * `gateway/platforms/mattermost.py` (873 LOC) → `plugins/platforms/mattermost/adapter.py` (git rename, R071) + appended `register()` block, hook helpers, and `_standalone_send` with media upload + thread_id support. * New `plugins/platforms/mattermost/{__init__.py, plugin.yaml}` with `requires_env` / `optional_env` declarations covering MATTERMOST_URL, MATTERMOST_TOKEN, MATTERMOST_ALLOWED_USERS, MATTERMOST_ALLOW_ALL_USERS, MATTERMOST_HOME_CHANNEL, MATTERMOST_REPLY_MODE, MATTERMOST_REQUIRE_MENTION, MATTERMOST_FREE_RESPONSE_CHANNELS, MATTERMOST_ALLOWED_CHANNELS. * `gateway/config.py`: delete 17-LOC `mattermost_cfg` YAML→env bridge (moved into plugin's `_apply_yaml_config`). * `gateway/run.py::_create_adapter`: delete `Platform.MATTERMOST elif` — replaced by the existing generic plugin-registry-first dispatch. * `tools/send_message_tool.py`: delete `_send_mattermost` (22 LOC) + `Platform.MATTERMOST elif` in `_send_to_platform` — the `else` branch already routes plugin platforms through `_send_via_adapter`, which hits the registry's `standalone_sender_fn`. * `hermes_cli/setup.py`: delete `_setup_mattermost` (44 LOC) — replaced by the plugin's `interactive_setup`. * `hermes_cli/gateway.py`: delete `_PLATFORMS["mattermost"]` dict entry (3 LOC) — plugin's `setup_fn` is dispatched via the plugin path in `_configure_platform`. * Consumer rewrite: 5 test files (test_mattermost.py, test_media_download_retry.py, test_send_multiple_images.py, test_stream_consumer.py, test_ws_auth_retry.py) get `gateway.platforms.mattermost` → `plugins.platforms.mattermost.adapter` with the bulk-rewrite recipe from the platform-plugin-migration playbook. Single `mock.patch` string in test_stream_consumer.py also repointed. * `tests/tools/test_send_message_missing_platforms.py`: thin `(token, extra, chat_id, message)` compat shim around the plugin's `_standalone_send(pconfig, …)` so existing test bodies continue to work without rewriting every signature. Validation ---------- * Plugin discovery: mattermost registers from `plugins/platforms/mattermost/` alongside discord / teams / irc / line / google_chat / simplex. All 9 hooks present (setup_fn, standalone_sender_fn, apply_yaml_config_fn, is_connected, check_fn, allowed_users_env, allow_all_env, cron_deliver_env_var, max_message_length=4000). * Mattermost-touching tests: 62/62 pass (`test_mattermost.py` + `test_send_message_missing_platforms.py`). * Targeted selectors (mattermost or platform_registry or stream_consumer or ws_auth_retry or media_download_retry or send_multiple_images or send_message_tool or platform_connected): 433/433 pass. * Full sweep (`scripts/run_tests.sh tests/gateway/ tests/cron/ tests/tools/test_send_message_tool.py tests/tools/test_send_message_missing_platforms.py tests/integration/`): **6220/6220 pass in 47.8s, 0 failures**. * Lint: ruff clean on all touched files. * Git identity verified: kshitijk4poor. * Rename detection: R071 (similarity dropped from a hypothetical R09x by the ~320-line appended register block — ~36% growth over the 873-LoC base, vs Discord's 5101 LoC base which kept R091). Closes part of #3823.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-method-override |
4 |
unresolved-import |
1 |
invalid-argument-type |
1 |
First entries
plugins/platforms/mattermost/adapter.py:910: [unresolved-import] unresolved-import: Cannot resolve imported module `aiohttp`
plugins/platforms/mattermost/adapter.py:392: [invalid-method-override] invalid-method-override: Invalid override of method `send_video`: Definition is incompatible with `BasePlatformAdapter.send_video`
plugins/platforms/mattermost/adapter.py:867: [invalid-argument-type] invalid-argument-type: Argument is incorrect: Expected `list[str]`, found `(list[str] & ~AlwaysFalsy) | None`
plugins/platforms/mattermost/adapter.py:352: [invalid-method-override] invalid-method-override: Invalid override of method `send_image_file`: Definition is incompatible with `BasePlatformAdapter.send_image_file`
plugins/platforms/mattermost/adapter.py:379: [invalid-method-override] invalid-method-override: Invalid override of method `send_voice`: Definition is incompatible with `BasePlatformAdapter.send_voice`
plugins/platforms/mattermost/adapter.py:365: [invalid-method-override] invalid-method-override: Invalid override of method `send_document`: Definition is incompatible with `BasePlatformAdapter.send_document`
✅ Fixed issues (6):
| Rule | Count |
|---|---|
invalid-method-override |
4 |
unresolved-import |
1 |
invalid-argument-type |
1 |
First entries
gateway/platforms/mattermost.py:379: [invalid-method-override] invalid-method-override: Invalid override of method `send_voice`: Definition is incompatible with `BasePlatformAdapter.send_voice`
gateway/platforms/mattermost.py:365: [invalid-method-override] invalid-method-override: Invalid override of method `send_document`: Definition is incompatible with `BasePlatformAdapter.send_document`
gateway/platforms/mattermost.py:809: [unresolved-import] unresolved-import: Cannot resolve imported module `aiohttp`
gateway/platforms/mattermost.py:392: [invalid-method-override] invalid-method-override: Invalid override of method `send_video`: Definition is incompatible with `BasePlatformAdapter.send_video`
gateway/platforms/mattermost.py:867: [invalid-argument-type] invalid-argument-type: Argument is incorrect: Expected `list[str]`, found `(list[str] & ~AlwaysFalsy) | None`
gateway/platforms/mattermost.py:352: [invalid-method-override] invalid-method-override: Invalid override of method `send_image_file`: Definition is incompatible with `BasePlatformAdapter.send_image_file`
Unchanged: 4845 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
This was referenced May 26, 2026
This was referenced Jun 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvage of #30916 — re-applied onto current main so the supply-chain audit (fixed in #31744) runs cleanly. Original commit + authorship preserved (@kshitijk4poor).
Migrates the Mattermost adapter from
gateway/platforms/mattermost.py(873-LOC built-in) toplugins/platforms/mattermost/{__init__.py, adapter.py, plugin.yaml}— second migration of an existing built-in into the bundled-plugin shape after Discord (#30591). Advances the umbrella refactor in #3823.Changes
gateway/platforms/mattermost.py(873 LOC) →plugins/platforms/mattermost/adapter.py(git rename, R071 — appended ~320-LOCregister()block + hook helpers +_standalone_sendwith media/thread support)plugins/platforms/mattermost/{__init__.py, plugin.yaml}— plugin shell,requires_env(URL + TOKEN) +optional_envdeclarationsregister(ctx)block + hook implementations to adapter:check_fn,is_connected,setup_fn,standalone_sender_fn,apply_yaml_config_fn(second consumer of refactor(plugins): add apply_yaml_config_fn registry hook for YAML→env config bridges #25443 after Discord), plus registry fieldsgateway/config.py: delete 17-LOCmattermost_cfgYAML→env bridge (moved into plugin's_apply_yaml_config)gateway/run.py::_create_adapter: deletePlatform.MATTERMOST elif(7 LOC) — replaced by the existing generic plugin-registry-first dispatchtools/send_message_tool.py: delete_send_mattermost(22 LOC) +Platform.MATTERMOST elifin_send_to_platform(2 LOC); theelsebranch already routes plugin platforms through_send_via_adapter→ registry'sstandalone_sender_fnhermes_cli/setup.py: delete_setup_mattermost(44 LOC) — replaced by the plugin'sinteractive_setuphermes_cli/gateway.py: delete_PLATFORMS["mattermost"]dict entry (3 LOC)gateway.platforms.mattermost→plugins.platforms.mattermost.adaptertests/tools/test_send_message_missing_platforms.py: thin compat shim around the plugin's_standalone_send14 files, +402 / −105.
What this fixes
_send_mattermostpreviously lived intools/send_message_tool.pyas a one-shot REST call with no thread support, no media upload, and no proxy awareness. The new plugin_standalone_send:root_idfield onPOST /postsmedia_filesviaPOST /files(multipart/form-data) and attaches the returnedfile_idvalues to the postMATTERMOST_PROXYenv via the sharedresolve_proxy_url+proxy_kwargs_for_aiohttphelpers (parity with Discord)Same capability bump as Discord's migration.
Validation
tests/gateway/ + send_message_*)hermes_cli/setup.py)Salvage notes
~29 open community PRs touch
gateway/platforms/mattermost.pyand will need to rebase onto the new path. Same cost as Discord migration (#30591 left 80 PRs to rebase) — established as acceptable.Closes part of #3823.
Closes #30916.
Infographic