Skip to content

MPT-19908: add /integration/installations service#281

Merged
d3rky merged 2 commits into
mainfrom
MPT-19908/integration-installations
May 8, 2026
Merged

MPT-19908: add /integration/installations service#281
d3rky merged 2 commits into
mainfrom
MPT-19908/integration-installations

Conversation

@albertsola
Copy link
Copy Markdown
Contributor

@albertsola albertsola commented Apr 7, 2026

Summary

Implements the /public/v1/integration/installations endpoint group as part of MPT-13310.

Changes

  • mpt_api_client/resources/integration/installations.pyInstallationsService / AsyncInstallationsService
  • mpt_api_client/resources/integration/mixins/installation_mixin.py — lifecycle actions: invite, install, uninstall, expire
  • Updated integration.py to expose installations property
  • Unit tests: tests/unit/resources/integration/test_installations.py + test_installation_mixin.py
  • E2e tests: tests/e2e/integration/installations/

Depends on

#277 (MPT-19892 — rename extensibility → integration)

⚠️ Draft — targets MPT-19892/e2e-extension-base-service until PR #277 merges.

Closes MPT-19908

  • Add InstallationsService and AsyncInstallationsService for /public/v1/integration/installations
  • Introduce Installation model (id, name, revision, account, extension, status, configuration, invitation, modules, terms, audit)
  • Add InstallationMixin and AsyncInstallationMixin exposing redeem lifecycle action
  • Expose installations property on Integration and AsyncIntegration
  • Add unit tests for installations service, installation mixin, and Integration/AsyncIntegration properties
  • Add e2e tests and fixtures for installations (sync and async) covering create/get/filter/redeem/delete flows
  • Add helper for decoding invitation payloads used by e2e tests
  • Update e2e_config.test.json: set integration.extension.id = EXT-6587-4477 and add integration.installation.id = EXI-0022-3978-5547
  • Update e2e fixtures to source extension clients from mpt_vendor and unskip several extension e2e tests (create/update/delete/download_icon)
  • Update pyproject.toml flake8 per-file-ignores for new e2e installation tests
  • Draft PR depends on PR MPT-19892: add E2E tests for Extension base service - Includes renaming from extensibility -> integrations #277 (MPT-19892 — rename extensibility → integration); currently targets MPT-19892/e2e-extension-base-service until merged

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 7, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an installations integration resource: Installation model, redeem mixins, InstallationsService/AsyncInstallationsService, Integration property wiring, unit and E2E tests, e2e fixtures/helpers, config entries, and a Flake8 per-file-ignore.

Changes

Installation Resource and Tests

Layer / File(s) Summary
Data Shape
mpt_api_client/resources/integration/installations.py
Adds Installation model with optional fields for metadata, references, lifecycle state, and related data.
Core Mixins
mpt_api_client/resources/integration/mixins/installation_mixin.py, mpt_api_client/resources/integration/mixins/__init__.py
Adds InstallationMixin and AsyncInstallationMixin with redeem method; exports both mixins from the package.
Service Config & Wiring
mpt_api_client/resources/integration/installations.py
Adds InstallationsServiceConfig (/public/v1/integration/installations, model Installation, collection key data) and InstallationsService/AsyncInstallationsService composed from mixins, managed-resource, and collection behaviors.
Integration Surface
mpt_api_client/resources/integration/integration.py, tests/unit/resources/integration/test_integration.py
Imports and exposes Integration.installations and AsyncIntegration.installations; unit tests updated to assert properties return correct service types.
Unit Tests: mixins & service
tests/unit/resources/integration/mixins/test_installation_mixin.py, tests/unit/resources/integration/test_installations.py
Adds tests that mock POSTs to validate mixin redeem behavior (sync/async), service composition and available methods, Installation model parsing for primitives and nested BaseModel fields, and a mocked create test.
E2E Fixtures / Helpers
tests/e2e/integration/installations/conftest.py, tests/e2e/integration/installations/helper.py, tests/e2e/integration/conftest.py
Adds sync/async installations_service fixtures, payload builders, create/teardown fixtures with best-effort delete handling, invitation payload decoding helper, and extension_id fixture sourced from e2e config.
E2E Tests for Installations
tests/e2e/integration/installations/test_sync_installations.py, tests/e2e/integration/installations/test_async_installations.py
Adds flaky-marked E2E tests for get/filter/create/redeem/delete flows (sync and async).
E2E Extensions Test Adjustments
tests/e2e/integration/extensions/conftest.py, tests/e2e/integration/extensions/test_sync_extensions.py, tests/e2e/integration/extensions/test_async_extensions.py
Switches extension fixtures to accept mpt_vendor/async_mpt_vendor and removes pytest.mark.skip from several extension create/update/delete/download tests.
Config
e2e_config.test.json
Updates integration.extension.id value and adds new integration.installation.id key.
Lint config
pyproject.toml
Adds Flake8 per-file-ignores for tests/e2e/integration/installations/*.py (WPS453 WPS202).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • softwareone-platform/mpt-api-python-client#277: Main PR and retrieved PR are related: both modify the integration API surface (same integration package/module), with the retrieved PR introducing the integration namespace/extension properties and the main PR adding an installations sub-service and mixin within that same integration module, so the changes operate on the same resource surface.
  • softwareone-platform/mpt-api-python-client#286: Both PRs modify the same config key (e2e_config.test.json → integration.extension.id updated to EXT-6587-4477).
  • softwareone-platform/mpt-api-python-client#285: Also modifies integration mixins exports and adds integration resource mixins in a related area.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Jira Issue Key In Title ✅ Passed PR title contains exactly one Jira issue key in the format MPT-XXXX: MPT-19908
Test Coverage Required ✅ Passed PR modifies 6 code files AND includes 11 test files. Test files are included, so check passes per custom check instructions.
Single Commit Required ✅ Passed PR contains exactly 1 commit (282c397), meeting the single commit requirement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Base automatically changed from MPT-19892/e2e-extension-base-service to main April 7, 2026 12:00
@albertsola albertsola force-pushed the MPT-19908/integration-installations branch 3 times, most recently from 7d07055 to f58b8f7 Compare April 7, 2026 16:28
@albertsola albertsola marked this pull request as ready for review April 7, 2026 16:29
@albertsola albertsola requested a review from a team as a code owner April 7, 2026 16:29
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/unit/resources/integration/mixins/test_installation_mixin.py (1)

46-66: Consider adding one case that verifies JSON payload forwarding.

These tests currently validate action routing and response parsing, but not that resource_data is sent through to post(..., json=...). Adding one payload case (sync + async) would close that gap.

Also applies to: 72-91

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/resources/integration/mixins/test_installation_mixin.py` around
lines 46 - 66, Add a test variant that checks the request JSON payload is
forwarded: in the test_post_actions function (and the async counterpart if
present), include a resource_data dict and call getattr(installation_service,
action)(installation_id, resource_data=resource_data) (or await for async), then
assert the mocked respx.post received json==resource_data (e.g., inspect
mock_route.calls[0].request.read() or .json()) and keep existing assertions on
method, call_count, and response parsing to ensure post(..., json=...) is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/e2e/integration/extensions/test_async_extensions.py`:
- Around line 9-11: The test file has three consecutive blank lines before the
top-level test function test_create_extension causing ruff format --check to
fail; edit the file to remove one blank line so there are exactly two blank
lines separating top-level definitions (ensure there are two blank lines
immediately before def test_create_extension and no leftover `@pytest.mark.skip`
or stray blank lines).

---

Nitpick comments:
In `@tests/unit/resources/integration/mixins/test_installation_mixin.py`:
- Around line 46-66: Add a test variant that checks the request JSON payload is
forwarded: in the test_post_actions function (and the async counterpart if
present), include a resource_data dict and call getattr(installation_service,
action)(installation_id, resource_data=resource_data) (or await for async), then
assert the mocked respx.post received json==resource_data (e.g., inspect
mock_route.calls[0].request.read() or .json()) and keep existing assertions on
method, call_count, and response parsing to ensure post(..., json=...) is used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 7638d5c8-b871-4f3d-b269-3aec3a657875

📥 Commits

Reviewing files that changed from the base of the PR and between f543c53 and f58b8f7.

📒 Files selected for processing (16)
  • e2e_config.test.json
  • mpt_api_client/resources/integration/installations.py
  • mpt_api_client/resources/integration/integration.py
  • mpt_api_client/resources/integration/mixins/__init__.py
  • mpt_api_client/resources/integration/mixins/installation_mixin.py
  • pyproject.toml
  • tests/e2e/integration/extensions/conftest.py
  • tests/e2e/integration/extensions/test_async_extensions.py
  • tests/e2e/integration/extensions/test_sync_extensions.py
  • tests/e2e/integration/installations/__init__.py
  • tests/e2e/integration/installations/conftest.py
  • tests/e2e/integration/installations/test_async_installations.py
  • tests/e2e/integration/installations/test_sync_installations.py
  • tests/unit/resources/integration/mixins/test_installation_mixin.py
  • tests/unit/resources/integration/test_installations.py
  • tests/unit/resources/integration/test_integration.py
💤 Files with no reviewable changes (1)
  • tests/e2e/integration/extensions/test_sync_extensions.py

Comment thread tests/e2e/integration/extensions/test_async_extensions.py
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

� Conflicts:
�	mpt_api_client/resources/integration/integration.py
�	mpt_api_client/resources/integration/mixins/__init__.py
�	tests/unit/resources/integration/test_integration.py
@albertsola albertsola force-pushed the MPT-19908/integration-installations branch from f58b8f7 to 5744f2b Compare May 5, 2026 13:06
@albertsola albertsola force-pushed the MPT-19908/integration-installations branch 2 times, most recently from 76009ff to 5be5e0c Compare May 6, 2026 17:42
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/unit/resources/integration/mixins/test_installation_mixin.py (1)

146-183: ⚡ Quick win

Add coverage for token_for_account() without account_id.

Current tests validate only the account_id-provided branch. Adding the no-arg path would cover the query_params=None branch and guard endpoint behavior for default account-token retrieval.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/resources/integration/mixins/test_installation_mixin.py` around
lines 146 - 183, Add tests covering the no-argument branch of token_for_account:
create both sync and async variants similar to test_token_for_account and
test_async_token_for_account but call installation_service.token_for_account()
and async_installation_service.token_for_account() with no arguments, set up
respx.post for the same URL without the params argument (so query_params is
None), mock the same httpx.Response payload, and assert mock_route.call_count ==
1 and result.to_dict() equals the expected_response; this ensures the
query_params=None branch is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unit/resources/integration/mixins/test_installation_mixin.py`:
- Around line 146-183: Add tests covering the no-argument branch of
token_for_account: create both sync and async variants similar to
test_token_for_account and test_async_token_for_account but call
installation_service.token_for_account() and
async_installation_service.token_for_account() with no arguments, set up
respx.post for the same URL without the params argument (so query_params is
None), mock the same httpx.Response payload, and assert mock_route.call_count ==
1 and result.to_dict() equals the expected_response; this ensures the
query_params=None branch is exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: c38a583e-85a1-4a99-b7da-c3478c68984d

📥 Commits

Reviewing files that changed from the base of the PR and between 76009ff and 5be5e0c.

📒 Files selected for processing (14)
  • e2e_config.test.json
  • mpt_api_client/resources/integration/mixins/installation_mixin.py
  • pyproject.toml
  • tests/e2e/integration/conftest.py
  • tests/e2e/integration/extensions/conftest.py
  • tests/e2e/integration/extensions/test_async_extensions.py
  • tests/e2e/integration/extensions/test_sync_extensions.py
  • tests/e2e/integration/installations/__init__.py
  • tests/e2e/integration/installations/conftest.py
  • tests/e2e/integration/installations/helper.py
  • tests/e2e/integration/installations/test_async_installations.py
  • tests/e2e/integration/installations/test_sync_installations.py
  • tests/unit/resources/integration/mixins/test_installation_mixin.py
  • tests/unit/resources/integration/test_installations.py
💤 Files with no reviewable changes (2)
  • tests/e2e/integration/extensions/test_async_extensions.py
  • tests/e2e/integration/extensions/test_sync_extensions.py

@albertsola albertsola force-pushed the MPT-19908/integration-installations branch from 5be5e0c to 282c397 Compare May 8, 2026 13:45
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 8, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/e2e/integration/installations/test_async_installations.py (1)

35-35: 💤 Low value

Consider simplifying the condition check.

Line 35 uses if not ... == instead of the more idiomatic !=. While functionally equivalent, the latter is clearer.

♻️ Optional simplification
-    if not invitation_payload.get("installationId") == async_created_installation_invite.id:
+    if invitation_payload.get("installationId") != async_created_installation_invite.id:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/integration/installations/test_async_installations.py` at line 35,
Replace the awkward equality-negation pattern by using the idiomatic inequality
operator: change the conditional that checks
invitation_payload.get("installationId") against
async_created_installation_invite.id from "if not ... == ..." to "if ... !=
..."; update the condition in the test (the line referencing
invitation_payload.get("installationId") and
async_created_installation_invite.id) accordingly so the logic remains identical
but reads more clearly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/e2e/integration/installations/test_async_installations.py`:
- Line 35: Replace the awkward equality-negation pattern by using the idiomatic
inequality operator: change the conditional that checks
invitation_payload.get("installationId") against
async_created_installation_invite.id from "if not ... == ..." to "if ... !=
..."; update the condition in the test (the line referencing
invitation_payload.get("installationId") and
async_created_installation_invite.id) accordingly so the logic remains identical
but reads more clearly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 9735441c-b072-4865-b7b3-3fcd080c699c

📥 Commits

Reviewing files that changed from the base of the PR and between 5be5e0c and 282c397.

📒 Files selected for processing (14)
  • e2e_config.test.json
  • mpt_api_client/resources/integration/mixins/installation_mixin.py
  • pyproject.toml
  • tests/e2e/integration/conftest.py
  • tests/e2e/integration/extensions/conftest.py
  • tests/e2e/integration/extensions/test_async_extensions.py
  • tests/e2e/integration/extensions/test_sync_extensions.py
  • tests/e2e/integration/installations/__init__.py
  • tests/e2e/integration/installations/conftest.py
  • tests/e2e/integration/installations/helper.py
  • tests/e2e/integration/installations/test_async_installations.py
  • tests/e2e/integration/installations/test_sync_installations.py
  • tests/unit/resources/integration/mixins/test_installation_mixin.py
  • tests/unit/resources/integration/test_installations.py
💤 Files with no reviewable changes (2)
  • tests/e2e/integration/extensions/test_sync_extensions.py
  • tests/e2e/integration/extensions/test_async_extensions.py
✅ Files skipped from review due to trivial changes (5)
  • tests/e2e/integration/conftest.py
  • pyproject.toml
  • tests/e2e/integration/extensions/conftest.py
  • e2e_config.test.json
  • tests/unit/resources/integration/mixins/test_installation_mixin.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • mpt_api_client/resources/integration/mixins/installation_mixin.py

@d3rky d3rky merged commit 6eb48b9 into main May 8, 2026
4 checks passed
@d3rky d3rky deleted the MPT-19908/integration-installations branch May 8, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants