Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2187152
feat: migrate to mitol-django-observability plugin
blarghmatey Mar 2, 2026
704c967
Merge branch 'master' into feat/mitol-django-observability
feoh Mar 24, 2026
9863b32
fix: Updcate uv lock
feoh Mar 24, 2026
d38f3c8
fix: regenerate app.json to remove MITXPRO_LOG_HOST/LOG_HOST_PORT
Copilot Mar 24, 2026
e1c483f
fix: apply prettier formatting to app.json
Copilot Mar 24, 2026
39f8e77
chore(deps): update dependency requests to v2.33.0 [security] (#3858)
renovate[bot] Mar 25, 2026
e78228d
Merge pull request #3821 from mitodl/feat/mitol-django-observability
feoh Mar 26, 2026
f93148a
[pre-commit.ci] pre-commit autoupdate (#3854)
pre-commit-ci[bot] Apr 2, 2026
0565689
fix(deps): update dependency ramda to ^0.32.0 (#3853)
renovate[bot] Apr 6, 2026
cac1cb0
chore(deps): update dependency lodash to v4.18.1 [security] (#3862)
renovate[bot] Apr 6, 2026
0585336
fix(deps): update dependency boto3 to v1.42.73 (#3871)
renovate[bot] Apr 6, 2026
264bb5c
chore(deps): update codecov/codecov-action digest to 75cd116 (#3864)
renovate[bot] Apr 6, 2026
aa40201
chore: add drf-lint pre-commit hook with baseline (#3861)
blarghmatey Apr 6, 2026
3150688
chore(deps): update actions/cache digest to 6682284 (#3863)
renovate[bot] Apr 6, 2026
03514c8
Merge branch 'release'
odlbot Apr 6, 2026
8b95ba8
Upgrade hubspot-api-client to 12.0.0 to fix ModuleNotFoundError: pkg_…
Copilot Apr 8, 2026
069339b
fix(deps): update dependency django to v4.2.30 [security] (#3873)
renovate[bot] Apr 9, 2026
9fb054a
Release 0.193.0
odlbot Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
SECRET_KEY: local_unsafe_key # pragma: allowlist secret

- name: Upload coverage to CodeCov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
with:
files: ./coverage.xml

Expand All @@ -111,7 +111,7 @@ jobs:
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT

- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
Expand Down Expand Up @@ -143,6 +143,6 @@ jobs:
run: node node_modules/webpack/bin/webpack.js --config webpack.config.prod.js --bail

- name: Upload test coverage to CodeCov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
with:
files: coverage/lcov.info
17 changes: 14 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ repos:
- id: check-toml
- id: debug-statements
- repo: https://github.com/scop/pre-commit-shfmt
rev: v3.12.0-2
rev: v3.13.0-1
hooks:
- id: shfmt
- repo: https://github.com/adrienverge/yamllint.git
Expand Down Expand Up @@ -51,7 +51,7 @@ repos:
- --exclude-files
- "_test.js$"
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.15.5"
rev: "v0.15.8"
hooks:
- id: ruff-format
- id: ruff
Expand Down Expand Up @@ -103,8 +103,19 @@ repos:
- id: shellcheck
args: ["--severity=warning"]
- repo: https://github.com/rhysd/actionlint
rev: v1.7.11
rev: v1.7.12
hooks:
- id: actionlint
name: actionlint
description: Runs actionlint to lint GitHub Actions workflow files
- repo: local
hooks:
- id: drf-serializer-orm-check
name: DRF Serializer ORM Check
description: "Detects Django ORM queries inside DRF serializer methods (N+1 risk)"
entry: drf-lint
args: [--baseline, drf_lint_baseline.json]
language: python
files: 'serializers\.py$'
additional_dependencies:
- mitol-drf-lint
18 changes: 18 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
Release Notes
=============

Version 0.193.0
---------------

- fix(deps): update dependency django to v4.2.30 [security] (#3873)
- Upgrade hubspot-api-client to 12.0.0 to fix ModuleNotFoundError: pkg_resources (#3860)
- chore(deps): update actions/cache digest to 6682284 (#3863)
- chore: add drf-lint pre-commit hook with baseline (#3861)
- chore(deps): update codecov/codecov-action digest to 75cd116 (#3864)
- fix(deps): update dependency boto3 to v1.42.73 (#3871)
- chore(deps): update dependency lodash to v4.18.1 [security] (#3862)
- fix(deps): update dependency ramda to ^0.32.0 (#3853)
- [pre-commit.ci] pre-commit autoupdate (#3854)
- chore(deps): update dependency requests to v2.33.0 [security] (#3858)
- fix: apply prettier formatting to app.json
- fix: regenerate app.json to remove MITXPRO_LOG_HOST/LOG_HOST_PORT
- fix: Updcate uv lock
- feat: migrate to mitol-django-observability plugin

Version 0.192.4 (Released April 06, 2026)
---------------

Expand Down
8 changes: 0 additions & 8 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -415,14 +415,6 @@
"description": "E-mail to use for the from field",
"required": false
},
"MITXPRO_LOG_HOST": {
"description": "Remote syslog server hostname",
"required": false
},
"MITXPRO_LOG_HOST_PORT": {
"description": "Remote syslog server port",
"required": false
},
"MITXPRO_LOG_LEVEL": {
"description": "The log level default",
"required": false
Expand Down
49 changes: 49 additions & 0 deletions drf_lint_baseline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[
"authentication/serializers.py:100:34:ORM001",
"courses/serializers.py:260:29:ORM002",
"courses/serializers.py:267:51:ORM002",
"courses/serializers.py:346:38:ORM002",
"courses/serializers.py:392:26:ORM002",
"courses/serializers.py:394:25:ORM002",
"courses/serializers.py:462:16:ORM001",
"courses/serializers.py:508:16:ORM001",
"courses/serializers.py:83:19:ORM002",
"ecommerce/serializers.py:1004:8:ORM002",
"ecommerce/serializers.py:1005:8:ORM001",
"ecommerce/serializers.py:1059:18:ORM002",
"ecommerce/serializers.py:1094:28:ORM002",
"ecommerce/serializers.py:1096:20:ORM002",
"ecommerce/serializers.py:1112:20:ORM001",
"ecommerce/serializers.py:1122:26:ORM001",
"ecommerce/serializers.py:1124:25:ORM001",
"ecommerce/serializers.py:114:22:ORM001",
"ecommerce/serializers.py:1169:28:ORM002",
"ecommerce/serializers.py:270:35:ORM002",
"ecommerce/serializers.py:275:16:ORM001",
"ecommerce/serializers.py:279:32:ORM002",
"ecommerce/serializers.py:287:27:ORM001",
"ecommerce/serializers.py:342:12:ORM001",
"ecommerce/serializers.py:354:24:ORM002",
"ecommerce/serializers.py:360:12:ORM002",
"ecommerce/serializers.py:377:24:ORM001",
"ecommerce/serializers.py:422:31:ORM002",
"ecommerce/serializers.py:469:21:ORM001",
"ecommerce/serializers.py:471:16:ORM002",
"ecommerce/serializers.py:473:16:ORM002",
"ecommerce/serializers.py:475:16:ORM002",
"ecommerce/serializers.py:483:16:ORM001",
"ecommerce/serializers.py:487:16:ORM001",
"ecommerce/serializers.py:492:16:ORM001",
"ecommerce/serializers.py:496:16:ORM001",
"ecommerce/serializers.py:575:12:ORM002",
"ecommerce/serializers.py:682:15:ORM001",
"ecommerce/serializers.py:691:12:ORM002",
"ecommerce/serializers.py:919:25:ORM002",
"ecommerce/serializers.py:938:15:ORM002",
"ecommerce/serializers.py:942:15:ORM002",
"ecommerce/serializers.py:998:8:ORM001",
"hubspot_xpro/serializers.py:267:35:ORM001",
"hubspot_xpro/serializers.py:275:36:ORM001",
"hubspot_xpro/serializers.py:276:23:ORM002",
"hubspot_xpro/serializers.py:282:15:ORM001"
]
49 changes: 25 additions & 24 deletions hubspot_xpro/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def test_sync_contact_with_hubspot(mock_hubspot_api):
== FAKE_HUBSPOT_ID
)
mock_hubspot_api.return_value.crm.objects.basic_api.create.assert_called_once_with(
simple_public_object_input=api.make_contact_sync_message(user.id),
simple_public_object_input_for_create=api.make_contact_sync_message(user.id),
object_type=api.HubspotObjectType.CONTACTS.value,
)

Expand All @@ -175,7 +175,7 @@ def test_sync_product_with_hubspot(mock_hubspot_api):
== FAKE_HUBSPOT_ID
)
mock_hubspot_api.return_value.crm.objects.basic_api.create.assert_called_once_with(
simple_public_object_input=api.make_product_sync_message(product.id),
simple_public_object_input_for_create=api.make_product_sync_message(product.id),
object_type=api.HubspotObjectType.PRODUCTS.value,
)

Expand All @@ -188,7 +188,9 @@ def test_sync_deal_with_hubspot(mocker, mock_hubspot_api, hubspot_order):
api.sync_deal_with_hubspot(hubspot_order.id)

mock_hubspot_api.return_value.crm.objects.basic_api.create.assert_called_once_with(
simple_public_object_input=api.make_deal_sync_message(hubspot_order.id),
simple_public_object_input_for_create=api.make_deal_sync_message(
hubspot_order.id
),
object_type=api.HubspotObjectType.DEALS.value,
)

Expand All @@ -212,12 +214,11 @@ def test_sync_line_item_with_hubspot(mock_hubspot_api, hubspot_order, hubspot_or
).hubspot_id
== FAKE_HUBSPOT_ID
)
mock_hubspot_api.return_value.crm.objects.associations_api.create.assert_called_once_with(
api.HubspotObjectType.LINES.value,
FAKE_HUBSPOT_ID,
api.HubspotObjectType.DEALS.value,
hubspot_order_id,
api.HubspotAssociationType.LINE_DEAL.value,
mock_hubspot_api.return_value.crm.associations.v4.basic_api.create_default.assert_called_once_with(
from_object_type=api.HubspotObjectType.LINES.value,
from_object_id=FAKE_HUBSPOT_ID,
to_object_type=api.HubspotObjectType.DEALS.value,
to_object_id=hubspot_order_id,
)


Expand All @@ -234,7 +235,9 @@ def test_b2b_sync_deal_with_hubspot(mocker, mock_hubspot_api, hubspot_b2b_order)
mock_sync_contact.assert_called_once()

mock_hubspot_api.return_value.crm.objects.basic_api.create.assert_called_once_with(
simple_public_object_input=api.make_b2b_deal_sync_message(hubspot_b2b_order.id),
simple_public_object_input_for_create=api.make_b2b_deal_sync_message(
hubspot_b2b_order.id
),
object_type=api.HubspotObjectType.DEALS.value,
)
assert (
Expand All @@ -250,12 +253,11 @@ def test_sync_b2b_line_with_hubspot(
):
"""Test that the hubspot CRM API is called properly for a b2b line sync"""
api.sync_b2b_line_with_hubspot(hubspot_b2b_order.id)
mock_hubspot_api.return_value.crm.objects.associations_api.create.assert_called_once_with(
api.HubspotObjectType.LINES.value,
FAKE_HUBSPOT_ID,
api.HubspotObjectType.DEALS.value,
hubspot_b2b_order_id,
api.HubspotAssociationType.LINE_DEAL.value,
mock_hubspot_api.return_value.crm.associations.v4.basic_api.create_default.assert_called_once_with(
from_object_type=api.HubspotObjectType.LINES.value,
from_object_id=FAKE_HUBSPOT_ID,
to_object_type=api.HubspotObjectType.DEALS.value,
to_object_id=hubspot_b2b_order_id,
)
assert (
api.HubspotObject.objects.get(
Expand All @@ -270,12 +272,11 @@ def test_sync_b2b_contact_with_hubspot(
):
"""Test that the hubspot CRM API is called properly for a contact sync"""
api.sync_b2b_contact_with_hubspot(hubspot_b2b_order.id)
mock_hubspot_api.return_value.crm.objects.associations_api.create.assert_called_once_with(
api.HubspotObjectType.DEALS.value,
hubspot_b2b_order_id,
api.HubspotObjectType.CONTACTS.value,
FAKE_HUBSPOT_ID,
api.HubspotAssociationType.DEAL_CONTACT.value,
mock_hubspot_api.return_value.crm.associations.v4.basic_api.create_default.assert_called_once_with(
from_object_type=api.HubspotObjectType.DEALS.value,
from_object_id=hubspot_b2b_order_id,
to_object_type=api.HubspotObjectType.CONTACTS.value,
to_object_id=FAKE_HUBSPOT_ID,
)


Expand Down Expand Up @@ -398,8 +399,8 @@ def test_sync_deal_hubspot_ids_to_hubspot(
mock_hubspot_api.return_value.crm.objects.basic_api.get_page.side_effect = [
mocker.Mock(results=deals, paging=None), # deals
]
mock_hubspot_api.return_value.crm.deals.associations_api.get_all.side_effect = [
*[mocker.Mock(results=[SimplePublicObjectFactory()]) for _ in line_items],
mock_hubspot_api.return_value.crm.associations.v4.basic_api.get_page.side_effect = [
*[mocker.Mock(results=[mocker.Mock(to_object_id=li.id)]) for li in line_items],
mocker.Mock(results=[]),
] # associations
mock_hubspot_api.return_value.crm.line_items.basic_api.get_by_id.side_effect = [
Expand Down
10 changes: 7 additions & 3 deletions hubspot_xpro/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from hubspot.crm.associations import BatchInputPublicAssociation, PublicAssociation
from hubspot.crm.objects import ApiException, BatchInputSimplePublicObjectInput
from hubspot.crm.objects import (
ApiException,
BatchInputSimplePublicObjectBatchInput,
BatchInputSimplePublicObjectBatchInputForCreate,
)
from mitol.common.decorators import single_task
from mitol.common.utils import chunks
from mitol.hubspot_api.api import HubspotApi, HubspotAssociationType, HubspotObjectType
Expand Down Expand Up @@ -347,7 +351,7 @@ def batch_create_hubspot_objects_chunked(
try:
response = HubspotApi().crm.objects.batch_api.create(
hubspot_type,
BatchInputSimplePublicObjectInput(
BatchInputSimplePublicObjectBatchInputForCreate(
inputs=[
api.MODEL_FUNCTION_MAPPING[ct_model_name](obj_id)
for obj_id in chunk
Expand Down Expand Up @@ -420,7 +424,7 @@ def batch_update_hubspot_objects_chunked(
for obj_id in chunk
]
response = HubspotApi().crm.objects.batch_api.update(
hubspot_type, BatchInputSimplePublicObjectInput(inputs=inputs)
hubspot_type, BatchInputSimplePublicObjectBatchInput(inputs=inputs)
)
updated_ids.extend([result.id for result in response.results])
except ApiException as ae:
Expand Down
10 changes: 7 additions & 3 deletions hubspot_xpro/tasks_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
from django.contrib.contenttypes.models import ContentType
from faker import Faker
from hubspot.crm.associations import BatchInputPublicAssociation, PublicAssociation
from hubspot.crm.objects import ApiException, BatchInputSimplePublicObjectInput
from hubspot.crm.objects import (
ApiException,
BatchInputSimplePublicObjectBatchInput,
BatchInputSimplePublicObjectBatchInputForCreate,
)
from mitol.hubspot_api.api import HubspotAssociationType, HubspotObjectType
from mitol.hubspot_api.exceptions import TooManyRequestsException
from mitol.hubspot_api.factories import HubspotObjectFactory, SimplePublicObjectFactory
Expand Down Expand Up @@ -228,7 +232,7 @@ def test_batch_update_hubspot_objects_chunked(mocker, id_count):
)
mock_hubspot_api.return_value.crm.objects.batch_api.update.assert_any_call(
HubspotObjectType.CONTACTS.value,
BatchInputSimplePublicObjectInput(
BatchInputSimplePublicObjectBatchInput(
inputs=[
{
"id": mock_id[1],
Expand Down Expand Up @@ -286,7 +290,7 @@ def test_batch_create_hubspot_objects_chunked(mocker, id_count):
)
mock_hubspot_api.return_value.crm.objects.batch_api.create.assert_any_call(
HubspotObjectType.CONTACTS.value,
BatchInputSimplePublicObjectInput(
BatchInputSimplePublicObjectBatchInputForCreate(
inputs=[
make_contact_sync_message(mock_id)
for mock_id in mock_ids[0 : min(id_count, 10)]
Expand Down
Loading
Loading