Skip to content

[Core] Send resync start event type in body#3028

Open
IdansPort wants to merge 6 commits intomainfrom
SEND_RESYNC_START-EVENT-TYPE-IN-BODY
Open

[Core] Send resync start event type in body#3028
IdansPort wants to merge 6 commits intomainfrom
SEND_RESYNC_START-EVENT-TYPE-IN-BODY

Conversation

@IdansPort
Copy link
Copy Markdown
Contributor

Description

What -

Why -

How -

Type of change

Please leave one option from the following and delete the rest:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • New Integration (non-breaking change which adds a new integration)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Non-breaking change (fix of existing functionality that will not change current behavior)
  • Documentation (added/updated documentation)

All tests should be run against the port production environment(using a testing org).

Core testing checklist

  • Integration able to create all default resources from scratch
  • Resync finishes successfully
  • Resync able to create entities
  • Resync able to update entities
  • Resync able to detect and delete entities
  • Scheduled resync able to abort existing resync and start a new one
  • Tested with at least 2 integrations from scratch
  • Tested with Kafka and Polling event listeners
  • Tested deletion of entities that don't pass the selector

Integration testing checklist

  • Integration able to create all default resources from scratch
  • Completed a full resync from a freshly installed integration and it completed successfully
  • Resync able to create entities
  • Resync able to update entities
  • Resync able to detect and delete entities
  • Resync finishes successfully
  • If new resource kind is added or updated in the integration, add example raw data, mapping and expected result to the examples folder in the integration directory.
  • If resource kind is updated, run the integration with the example data and check if the expected result is achieved
  • If new resource kind is added or updated, validate that live-events for that resource are working as expected
  • Docs PR link here

Preflight checklist

  • Handled rate limiting
  • Handled pagination
  • Implemented the code in async
  • Support Multi account

Screenshots

Include screenshots from your environment showing how the resources of the integration will look.

API Documentation

Provide links to the API documentation used for this integration.

@IdansPort IdansPort requested a review from a team as a code owner March 29, 2026 11:49
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Send event_type and resync_start_time in lakehouse API requests
✨ Enhancement

Grey Divider

Walkthroughs

Description
• Replace data_type parameter with event_type enum in lakehouse API
• Add resync_start_time parameter to track event creation timestamps
• Implement timestamp validation to prevent future timestamps
• Add comprehensive timestamp tracking to webhook events and raw results
Diagram
flowchart LR
  A["Webhook/Resync Event"] -->|"created_at timestamp"| B["WebhookEvent"]
  B -->|"propagate timestamp"| C["WebhookEventRawResults"]
  C -->|"resync_start_time + event_type"| D["post_integration_raw_data"]
  D -->|"validate timestamp"| E["Validation Layer"]
  E -->|"add to request body"| F["Lakehouse API"]
  G["LakehouseEventType Enum"] -->|"RESYNC or LIVE_EVENT"| D
Loading

Grey Divider

File Changes

1. port_ocean/clients/port/mixins/integrations.py ✨ Enhancement +30/-5

Add event_type and resync_start_time to lakehouse API

port_ocean/clients/port/mixins/integrations.py


2. port_ocean/core/models.py ✨ Enhancement +5/-0

Create LakehouseEventType enum with RESYNC and LIVE_EVENT

port_ocean/core/models.py


3. port_ocean/core/handlers/webhook/webhook_event.py ✨ Enhancement +16/-0

Add created_at timestamp tracking to webhook events

port_ocean/core/handlers/webhook/webhook_event.py


View more (8)
4. port_ocean/core/handlers/webhook/processor_manager.py ✨ Enhancement +1/-0

Propagate webhook event created_at to raw results

port_ocean/core/handlers/webhook/processor_manager.py


5. port_ocean/core/integrations/mixins/live_events.py ✨ Enhancement +5/-3

Update live events to use event_type and resync_start_time

port_ocean/core/integrations/mixins/live_events.py


6. port_ocean/core/integrations/mixins/sync_raw.py ✨ Enhancement +11/-3

Update resync to use event_type and resync_start_time

port_ocean/core/integrations/mixins/sync_raw.py


7. port_ocean/tests/clients/port/mixins/test_integrations_lakehouse.py 🧪 Tests +0/-54

Remove data_type tests and update to new parameters

port_ocean/tests/clients/port/mixins/test_integrations_lakehouse.py


8. port_ocean/tests/core/handlers/mixins/test_live_events_lakehouse.py 🧪 Tests +18/-9

Update live events tests for event_type and resync_start_time

port_ocean/tests/core/handlers/mixins/test_live_events_lakehouse.py


9. port_ocean/tests/core/test_resync_webhook_timestamp_tracking.py 🧪 Tests +486/-0

Add comprehensive tests for timestamp and event type tracking

port_ocean/tests/core/test_resync_webhook_timestamp_tracking.py


10. pyproject.toml ⚙️ Configuration changes +1/-1

Bump version to 0.38.26

pyproject.toml


11. CHANGELOG.md 📝 Documentation +7/-1

Document event_type and resync_start_time improvements

CHANGELOG.md


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review bot commented Mar 29, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. New tests call non-existent isotime🐞 Bug ✓ Correctness
Description
test_resync_webhook_timestamp_tracking asserts request_body["type"] and calls datetime.isotime(),
which will fail (KeyError/AttributeError) because the implementation sets eventType and serializes
timestamps via isoformat().
Code

port_ocean/tests/core/test_resync_webhook_timestamp_tracking.py[R221-273]

+        # Verify the request body
+        request_body = call_args.kwargs["json"]
+        assert request_body["items"] == raw_data
+        assert request_body["operation"] == "upsert"
+        assert request_body["type"] == "resync"
+        assert request_body["resyncStartTime"] == resync_time.isotime()
+        assert request_body["eventType"] == "resync"
+        assert "extractionTimestamp" in request_body
+
+    @pytest.mark.asyncio
+    async def test_request_body_with_live_event_type(self):
+        """Verify request body includes resyncStartTime and eventType for webhook"""
+        mock_client = AsyncMock()
+        mock_client.post = AsyncMock(return_value=MagicMock(status_code=200))
+        mock_auth = MagicMock()
+        mock_auth.headers = AsyncMock(return_value={"Authorization": "Bearer test"})
+        mock_auth.ingest_url = "https://test.example.com"
+        mock_auth.integration_type = "github"
+
+        mixin = IntegrationClientMixin(
+            integration_identifier="test-integration-123",
+            integration_version="1.0.0",
+            auth=mock_auth,
+            client=mock_client,
+        )
+
+        webhook_time = datetime(2024, 3, 29, 10, 30, 0, tzinfo=timezone.utc)
+        raw_data = [{"name": "updated-repo", "stars": 150}]
+
+        with patch(
+            "port_ocean.clients.port.mixins.integrations.handle_port_status_code"
+        ):
+            await mixin.post_integration_raw_data(
+                raw_data=raw_data,
+                sync_id="webhook-xyz-789",
+                kind="repository",
+                operation=LakehouseOperation.UPSERT,
+                kafka_metadata={"originalWebhook": {"event": "push"}},
+                resync_start_time=webhook_time,
+                event_type=LakehouseEventType.LIVE_EVENT,
+            )
+
+        # Verify the call was made
+        assert mock_client.post.called
+        call_args = mock_client.post.call_args
+
+        # Verify the request body
+        request_body = call_args.kwargs["json"]
+        assert request_body["items"] == raw_data
+        assert request_body["operation"] == "upsert"
+        assert request_body["type"] == "live-event"
+        assert request_body["resyncStartTime"] == webhook_time.isotime()
+        assert request_body["eventType"] == "live-event"
Evidence
The new tests check keys/methods that don't exist: the request body does not include "type" and
datetime has no isotime() method; the implementation uses resync_start_time.isoformat() and
event_type.value under "eventType".

port_ocean/tests/core/test_resync_webhook_timestamp_tracking.py[185-276]
port_ocean/clients/port/mixins/integrations.py[317-327]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`test_resync_webhook_timestamp_tracking.py` contains incorrect assertions and a non-existent datetime method call:
- Asserts `request_body["type"]` even though the implementation does not set it.
- Uses `resync_time.isotime()` / `webhook_time.isotime()` which will raise `AttributeError`.

### Issue Context
The production code emits:
- `resyncStartTime` as `datetime.isoformat()`
- `eventType` as `LakehouseEventType.<...>.value`

### Fix Focus Areas
- port_ocean/tests/core/test_resync_webhook_timestamp_tracking.py[185-276]
- port_ocean/clients/port/mixins/integrations.py[317-327]

### Expected changes
- Replace `request_body["type"]` assertions with `request_body["eventType"]`.
- Replace `.isotime()` with `.isoformat()`.
- Ensure assertions match the actual serialized output (`resyncStartTime` should equal the exact isoformat string sent).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unnormalized resyncStartTime serialized 🐞 Bug ✓ Correctness
Description
post_integration_raw_data normalizes resync_start_time to UTC for the future-time check, but then
serializes the original resync_start_time into the request body, which can emit naive timestamps or
non-UTC offsets despite the UTC intent.
Code

port_ocean/clients/port/mixins/integrations.py[R298-314]

+        if resync_start_time is not None:
+            # Normalize both timestamps to UTC for comparison
+            # If resync_start_time is naive, treat it as UTC
+            if resync_start_time.tzinfo is None:
+                resync_time_utc = resync_start_time.replace(tzinfo=timezone.utc)
+            else:
+                resync_time_utc = resync_start_time
+
+            now_utc = datetime.now(timezone.utc)
+            if resync_time_utc > now_utc:
+                raise ValueError(
+                    f"resync_start_time cannot be in the future: {resync_start_time}"
+                )
+
        logger.debug(
            "starting POST raw data request", raw_data=raw_data, operation=operation
        )
Evidence
The function computes resync_time_utc (including adding tzinfo for naive datetimes) but does not
use it for serialization; it uses resync_start_time.isoformat() instead, so a naive datetime will
be sent without timezone information.

port_ocean/clients/port/mixins/integrations.py[298-327]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`post_integration_raw_data` normalizes `resync_start_time` into `resync_time_utc` for validation, but serializes `resync_start_time` (not the normalized value) into `body['resyncStartTime']`. This can produce inconsistent output when callers pass naive datetimes or non-UTC tz-aware datetimes.

### Issue Context
The code already computes a normalized value for comparison; it should reuse that for serialization to keep validation/serialization consistent.

### Fix Focus Areas
- port_ocean/clients/port/mixins/integrations.py[298-327]

### Expected changes
- Normalize with:
 - `resync_time_utc = resync_start_time.replace(tzinfo=timezone.utc)` when naive
 - otherwise `resync_time_utc = resync_start_time.astimezone(timezone.utc)`
- Serialize `body['resyncStartTime'] = resync_time_utc.isoformat()`.
- (Optional consistency) compute `extractionTimestamp` using `datetime.now(timezone.utc)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@IdansPort IdansPort changed the title Send resync start event type in body [Core] Send resync start event type in body Mar 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/23708831872/artifacts/6165755538

Code Coverage Total Percentage: 90.58%

@github-actions
Copy link
Copy Markdown
Contributor

Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/23709507124/artifacts/6165931713

Code Coverage Total Percentage: 90.58%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant