Skip to content

Upmerge v9.0.1 from nyaruka/mailroom - #704

Merged
rowanseymour merged 1 commit into
mainfrom
upmerge-v9.0.1
Apr 20, 2026
Merged

rowanseymour merged 1 commit into
mainfrom
upmerge-v9.0.1

Conversation

@rowanseymour

Copy link
Copy Markdown
Contributor

Automated upmerge of the latest v9.0.1 tag from nyaruka/mailroom (BSL) to the AGPL mirror.

Copilot AI review requested due to automatic review settings April 20, 2026 21:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Automated upmerge of nyaruka/mailroom v9.0.1 into the AGPL mirror, including substantial internal refactors (cron abstraction, DB access types), logging migration to slog, and removal of several ticket-service implementations/tests.

Changes:

  • Introduces a core/tasks cron interface + shared CronNext scheduling helper; updates multiple cron jobs to return structured results.
  • Refactors many model loaders and handlers (types, DB interfaces, logging with slog, move to any, new opt-in assets support).
  • Updates build/runtime dependencies and tooling (Go 1.21, PostGIS 15 in CI, Dockerfile docs fetch).

Reviewed changes

Copilot reviewed 226 out of 301 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
services/tickets/rocketchat/web_test.go Removes RocketChat ticketing web test as part of ticketing service removals
services/tickets/rocketchat/web.go Removes RocketChat webhook handler and route registration
services/tickets/rocketchat/testdata/TestOpenAndForward_open_ticket.snap Removes RocketChat snapshot fixture
services/tickets/rocketchat/testdata/TestOpenAndForward_forward_message.snap Removes RocketChat snapshot fixture
services/tickets/rocketchat/testdata/TestCloseAndReopen_close_tickets.snap Removes RocketChat snapshot fixture
services/tickets/rocketchat/service.go Removes RocketChat ticket service implementation
services/tickets/rocketchat/client_test.go Removes RocketChat client tests
services/tickets/rocketchat/client.go Removes RocketChat client implementation
services/tickets/mailgun/web_test.go Removes Mailgun ticketing web test
services/tickets/mailgun/testdata/TestSendMessage_mailgun_request.snap Removes Mailgun snapshot fixture
services/tickets/mailgun/testdata/TestOpenAndForward_open_ticket.snap Removes Mailgun snapshot fixture
services/tickets/mailgun/testdata/TestOpenAndForward_forward_message.snap Removes Mailgun snapshot fixture
services/tickets/mailgun/testdata/TestCloseAndReopen_reopen_tickets.snap Removes Mailgun snapshot fixture
services/tickets/mailgun/testdata/TestCloseAndReopen_close_tickets.snap Removes Mailgun snapshot fixture
services/tickets/mailgun/client_test.go Removes Mailgun client tests
services/tickets/mailgun/client.go Removes Mailgun client implementation
services/tickets/intern/service_test.go Removes internal ticket service tests
services/tickets/intern/service.go Removes internal ticket service implementation
services/ivr/vonage/service_test.go Updates tests to use any for decoded JSON
services/ivr/twiml/client.go Switches TwiML XML inner payload type to any
runtime/runtime.go Changes ReadonlyDB type from *sqlx.DB to *sql.DB
runtime/config_test.go Removes invalid IP/network test cases for disallowed networks parsing
runtime/config.go Replaces custom network parsing with httpx.ParseNetworks
goreleaser.yml Restructures GoReleaser config keys (schema change)
core/tasks/timeouts/cron_test.go Updates timeout cron test to new cron interface/result
core/tasks/timeouts/cron.go Refactors timeouts cron into tasks.Cron implementation
core/tasks/starts/start_flow_test.go Updates flow start construction signature
core/tasks/starts/start_flow.go Refactors start batching (priority changes, flow type handling, slog logging, i18n language)
core/tasks/msgs/send_broadcast_batch.go Switches to slog and queues messages instead of sending directly
core/tasks/msgs/send_broadcast.go Switches error logging to slog
core/tasks/msgs/retry_errored_messages_test.go Updates retry cron test to new cron interface/result and new msg struct usage
core/tasks/msgs/retry_errored_messages.go Refactors retry cron into tasks.Cron and queues messages
core/tasks/ivr/start_ivr_flow_batch_test.go Updates flow start signature and IVR service interface
core/tasks/ivr/start_ivr_flow_batch.go Migrates IVR batch logging to slog
core/tasks/ivr/cron_test.go Updates IVR retry cron test to new cron interface/result
core/tasks/ivr/cron.go Refactors IVR retry cron into tasks.Cron and migrates to slog
core/tasks/interrupts/interrupt_channel_test.go Updates retry invocation to new cron interface
core/tasks/interrupts/interrupt_channel.go Fixes DB handle usage to match new DB abstractions
core/tasks/incidents/end_incidents_test.go Updates incidents cron test to new cron interface/result
core/tasks/incidents/end_incidents.go Refactors incidents cron into tasks.Cron and adds ended count result
core/tasks/handler/cron_test.go Updates handler retry cron test to new cron interface/result and reset flags
core/tasks/handler/cron.go Refactors handler retry cron into tasks.Cron and migrates to slog
core/tasks/cron_test.go Adds unit tests for tasks.CronNext
core/tasks/cron.go Introduces tasks.Cron interface and CronNext helper
core/tasks/contacts/populate_dynamic_group.go Migrates smart group task logging to slog
core/tasks/contacts/import_contact_batch_test.go Updates assert maps to map[string]any
core/tasks/campaigns/fire_campaign_event.go Migrates campaign event worker logging to slog and updates marker API
core/tasks/analytics/cron.go Refactors analytics cron into tasks.Cron and returns stats map
core/search/search.go Migrates search debug logging to slog
core/search/queries.go Updates locale formatting call for new locale type
core/search/groups.go Migrates group sleep logging to slog
core/runner/runner_test.go Updates flow start batching and language types (i18n)
core/queue/queue_test.go Moves queue tests to external package and updates API calls
core/queue/queue.go Reorders priority constants and updates AddTask signature to any
core/msgio/send_test.go Renames send test to queue test; updates channel setup and queueing assertions
core/msgio/android_test.go Refactors Android sync test to per-channel function and changes mock auth status
core/msgio/android.go Replaces bulk Android sync with SyncAndroidChannel returning errors; uses slog
core/models/webhook_event_test.go Adds cleanup to webhook event test
core/models/webhook_event.go Updates DB interface type and uses any slice
core/models/utils_test.go Adjusts test cleanup and uses []any
core/models/users.go Refactors user asset loading to *sql.DB + JSON row scanning helper; updates null lib
core/models/topics.go Refactors topic asset loading to *sql.DB + JSON row scanning helper; updates null lib
core/models/tokens.go Updates DB interface type
core/models/ticket_events_test.go Updates ticket insert helper signature and null lib version
core/models/ticket_events.go Updates DB interface type and uses any slice
core/models/templates_test.go Updates locale types and template expectations; adds template lookup asserts
core/models/teams.go Updates null lib version
core/models/starts_test.go Updates flow start signature and batch creation signature
core/models/starts.go Removes FlowType from FlowStart, updates DB interfaces, changes CreateBatch signature
core/models/runs.go Updates null lib version
core/models/resthooks.go Refactors resthook loading to *sql.DB + JSON row scanning helper
core/models/orgs_test.go Refactors org loading to use *sql.DB and new environment accessors
core/models/optins_test.go Adds tests for opt-in asset loading
core/models/optins.go Adds opt-in model + loader using *sql.DB + JSON row scanning helper
core/models/notifications_test.go Updates ticket insert helper signature
core/models/notifications.go Adds medium field, typed EmailStatus, updates insert SQL and DB interfaces
core/models/locations_test.go Updates location name lookup to pass environment
core/models/locations.go Refactors location loading to use *sql.DB and env-aware hierarchy parsing; uses slog
core/models/labels.go Refactors label loading to *sql.DB + JSON row scanning helper
core/models/incident.go Updates DB interfaces and null lib version; changes open incidents query signature
core/models/imports_test.go Uses dbutil helper to scan IDs from *sql.Rows
core/models/http_logs_test.go Removes HTTPLogger test coverage for ticketer-called logs
core/models/http_logs.go Removes ticketer log type and HTTPLogger; updates insert SQL and DB interfaces
core/models/groups_test.go Refactors group loading test to use org assets instead of mock DB
core/models/globals.go Refactors globals loading to *sql.DB + JSON row scanning helper
core/models/flows_test.go Updates flow loaders to accept *sql.DB
core/models/flows.go Refactors flow loading to *sql.DB, migrates to slog, updates null map type, adjusts revision selection SQL
core/models/flow_stats_test.go Updates redis key assertions API usage
core/models/fields.go Refactors field loading to *sql.DB + JSON row scanning helper (signature change)
core/models/counts.go Updates DB interface type
core/models/channels_test.go Updates channel expectations (Facebook channel + features; removes parent checks)
core/models/channel_event_test.go Updates channel event API with opt-in ID and adds extra string helper checks
core/models/assets_test.go Updates expected flow definition prefix for clone
core/models/airtime_test.go Updates assert map types to map[string]any
core/models/airtime.go Updates DB interface type and uses any slice
core/hooks/update_campaign_events.go Updates hook signature to []any and migrates debug logging to slog
core/hooks/unsubscribe_resthook.go Updates hook signature to []any
core/hooks/start_start.go Updates hook signature to []any
core/hooks/start_broadcasts.go Updates hook signature to []any
core/hooks/send_messages.go Updates hook signature to []any and queues messages
core/hooks/monitor_webhooks.go Updates hook signature to []any
core/hooks/insert_webhook_event.go Updates hook signature to []any
core/hooks/insert_tickets.go Updates hook signature to []any
core/hooks/insert_start.go Updates hook signature to []any and flow start creation signature
core/hooks/insert_http_logs.go Updates hook signature to []any
core/hooks/insert_airtime_transfers.go Updates hook signature to []any
core/hooks/contact_modified.go Updates hook signature to []any
core/hooks/contact_last_seen.go Updates hook signature to []any
core/hooks/commit_urn_changes.go Updates hook signature to []any
core/hooks/commit_status_changes.go Updates hook signature to []any
core/hooks/commit_name_changes.go Updates hook signature to []any and null lib version
core/hooks/commit_messages.go Updates hook signature to []any
core/hooks/commit_language_changes.go Updates hook signature to []any and null lib version
core/hooks/commit_ivr.go Updates hook signature to []any
core/hooks/commit_group_changes.go Updates hook signature to []any
core/hooks/commit_flow_changes.go Updates hook signature to []any
core/hooks/commit_field_changes.go Updates hook signature, uses any collections, migrates debug logging to slog
core/hooks/commit_added_labels.go Updates hook signature to []any
core/handlers/webhook_called_test.go Updates SQL assertion arg types and contact load signature
core/handlers/webhook_called.go Migrates debug logging to slog
core/handlers/ticket_opened_test.go Removes ticket service imports & ticketer assertions; updates SQL assertions/args
core/handlers/ticket_opened.go Removes ticketer lookup usage and migrates logging to slog
core/handlers/sprint_ended.go Adds slog debug log for sprint end
core/handlers/session_triggered_test.go Updates SQL assertion arg types
core/handlers/session_triggered.go Migrates debug logging to slog
core/handlers/service_called_test.go Updates SQL assertion arg types
core/handlers/service_called.go Migrates logging to slog; removes ticketer HTTP log handling
core/handlers/resthook_called.go Migrates logging to slog and changes missing resthook logging level/message
core/handlers/optin_requested_test.go Adds opt-in requested handler test and queue assertions
core/handlers/optin_requested.go Adds handler for opt-in requested events
core/handlers/noop.go Import ordering cleanup
core/handlers/msg_received_test.go Updates to use .FlowMsg and []any args
core/handlers/msg_received.go Migrates logging to slog
core/handlers/msg_created.go Migrates logging to slog; passes template to outgoing msg creation
core/handlers/ivr_created.go Migrates logging to slog
core/handlers/input_labels_added_test.go Updates to use .FlowMsg, new msg IDs, []any args
core/handlers/input_labels_added.go Migrates logging to slog
core/handlers/flow_entered_test.go Updates SQL assertion arg types
core/handlers/flow_entered.go Migrates debug logging to slog
core/handlers/email_sent.go Migrates email sent logging to slog
core/handlers/contact_urns_changed_test.go Updates contact URN insert helper signature and SQL arg types
core/handlers/contact_urns_changed.go Migrates logging to slog
core/handlers/contact_status_changed_test.go Updates SQL assertion arg types
core/handlers/contact_status_changed.go Migrates logging to slog
core/handlers/contact_name_changed_test.go Updates SQL assertion arg types
core/handlers/contact_name_changed.go Migrates logging to slog
core/handlers/contact_language_changed_test.go Updates SQL assertion arg types
core/handlers/contact_language_changed.go Migrates logging to slog
core/handlers/contact_groups_changed_test.go Updates SQL assertion arg types
core/handlers/contact_groups_changed.go Migrates logging to slog and improves warning fields
core/handlers/contact_field_changed_test.go Updates SQL assertion arg types
core/handlers/contact_field_changed.go Migrates logging to slog
core/handlers/campaigns_test.go Updates SQL assertion arg types
core/handlers/broadcast_created_test.go Updates SQL assertion arg types
core/handlers/broadcast_created.go Migrates logging to slog
core/handlers/base_test.go Updates SQL assertion arg types and engine/modifiers invocation
core/handlers/airtime_transferred_test.go Updates SQL assertion arg types
core/handlers/airtime_transferred.go Migrates logging to slog
core/goflow/modifiers_test.go Import ordering cleanup
core/goflow/modifiers.go Import spacing cleanup
core/goflow/flows_test.go Updates language type to i18n and organizes imports
core/goflow/flows.go Import ordering cleanup
core/goflow/engine_test.go Removes simulator ticket test and related imports
core/goflow/engine.go Removes ticket factory/service; configures max field/result chars
cmd/test-smtp/main.go Migrates to slog and adjusts fatal error handling
Dockerfile Updates Go version and fetches goflow docs at build time
.github/workflows/ci.yml Updates Go version and PostGIS version used by CI
Comments suppressed due to low confidence (1)

core/tasks/analytics/cron.go:1

  • redis_wait_count is returning dbWaitCountInPeriod instead of redisWaitCountInPeriod, which will report incorrect Redis wait counts.
package analytics

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/tasks/cron.go
Comment on lines +26 to +36
func CronNext(last time.Time, interval time.Duration) time.Time {
if interval >= time.Second && interval < time.Minute {
return last.Add(interval - ((time.Duration(last.Second()) * time.Second) % interval))
} else if interval == time.Minute {
seconds := time.Duration(60-last.Second()) + 1
return last.Add(seconds * time.Second)
} else {
// no special treatment for other things
return last.Add(interval)
}
}

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

The sub-minute scheduling math is incorrect because it only uses last.Second() and ignores the current sub-second offset; e.g. for 150ms intervals it can schedule earlier than expected within the same second. Consider computing the next fire based on last.UnixNano() modulo interval (or using last.Truncate(interval).Add(interval) with care for exact alignment) so that nanoseconds are accounted for.

Copilot uses AI. Check for mistakes.
Comment thread core/tasks/ivr/cron.go
Comment on lines 38 to 50
throttledChannels := make(map[models.ChannelID]bool)
clogs := make([]*models.ChannelLog, 0, len(calls))

// schedules requests for each call
for _, call := range calls {
log = log.WithField("call_id", call.ID())
log = log.With("call_id", call.ID())

// if the channel for this call is throttled, move on
if throttledChannels[call.ChannelID()] {
call.MarkThrottled(ctx, rt.DB, time.Now())
log.WithField("channel_id", call.ChannelID()).Info("skipping call, throttled")
log.Info("skipping call, throttled", "channel_id", call.ChannelID())
continue
}

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

Reassigning log = log.With(\"call_id\", ...) inside the loop can cause attributes to accumulate across iterations with slog (duplicate call_id keys across logs). Prefer creating a per-iteration logger (e.g. callLog := log.With(...)) and use callLog for the rest of the loop body.

Copilot uses AI. Check for mistakes.
Comment thread cmd/test-smtp/main.go
err = smtpx.Send(client, m, nil)
if err != nil {
logrus.WithError(err).Fatal("error sending email")
slog.Error("error sending email", "error", err)

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

On send failure the program logs the error but continues and exits with status 0 (and still logs "email sent"). Previously this path was fatal. Consider returning early and exiting non-zero when smtpx.Send fails.

Suggested change
slog.Error("error sending email", "error", err)
slog.Error("error sending email", "error", err)
os.Exit(1)

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile
Comment on lines +15 to +16
RUN grep goflow go.mod | cut -d" " -f2 | cut -c2- > /tmp/goflow_version
RUN curl -L "https://github.com/nyaruka/goflow/releases/download/v`cat /tmp/goflow_version`/docs.tar.gz" | tar zxv

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

Fetching and extracting a remote tarball at build time without integrity verification makes builds non-reproducible and increases supply-chain risk. Consider pinning a checksum/signature verification step (or vendoring the docs artifact) before extracting.

Suggested change
RUN grep goflow go.mod | cut -d" " -f2 | cut -c2- > /tmp/goflow_version
RUN curl -L "https://github.com/nyaruka/goflow/releases/download/v`cat /tmp/goflow_version`/docs.tar.gz" | tar zxv
ARG GOFLOW_DOCS_SHA256
RUN grep goflow go.mod | cut -d" " -f2 | cut -c2- > /tmp/goflow_version
RUN version="$(cat /tmp/goflow_version)" \
&& curl -fL "https://github.com/nyaruka/goflow/releases/download/v${version}/docs.tar.gz" -o /tmp/docs.tar.gz \
&& echo "${GOFLOW_DOCS_SHA256} /tmp/docs.tar.gz" | sha256sum -c - \
&& tar zxvf /tmp/docs.tar.gz \
&& rm -f /tmp/docs.tar.gz

Copilot uses AI. Check for mistakes.
Comment thread goreleaser.yml
Comment on lines +1 to +3
build:
main: ./cmd/mailroom/main.go
binary: mailroom

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

This appears to change the GoReleaser config schema (e.g., removing version: 2 and the builds: list). Unless the repository has also upgraded to a GoReleaser version/config format that supports build: at the root, this will likely break releases. Please confirm the intended GoReleaser schema and adjust the config accordingly.

Copilot uses AI. Check for mistakes.
Comment thread core/models/users.go
rows, err := db.QueryContext(ctx, sqlSelectUsersByOrg, orgID)
if err != nil && err != sql.ErrNoRows {
return nil, errors.Wrapf(err, "error querying users for org: %d", orgID)
}

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

rows is no longer explicitly closed (previously defer rows.Close() was used). If ScanJSONRows doesn't guarantee closing the *sql.Rows, this can leak DB resources. Either ensure ScanJSONRows closes rows in all cases, or add defer rows.Close() here (and in the other loaders using the same pattern).

Suggested change
}
}
if rows != nil {
defer rows.Close()
}

Copilot uses AI. Check for mistakes.
@codecov-commenter

codecov-commenter commented Apr 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.20946% with 384 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.09%. Comparing base (7f86e1c) to head (43a7fc5).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
core/models/msgs.go 39.28% 47 Missing and 4 partials ⚠️
core/tasks/handler/contact_tasks.go 60.49% 27 Missing and 5 partials ⚠️
core/runner/runner.go 25.00% 16 Missing and 2 partials ⚠️
core/tasks/schedules/cron.go 51.35% 16 Missing and 2 partials ⚠️
core/models/contacts.go 79.51% 15 Missing and 2 partials ⚠️
core/tasks/expirations/cron.go 46.66% 16 Missing ⚠️
core/models/broadcasts.go 74.07% 11 Missing and 3 partials ⚠️
core/models/schedules.go 17.64% 14 Missing ⚠️
services/ivr/vonage/service.go 26.31% 14 Missing ⚠️
core/models/campaigns.go 36.84% 12 Missing ⚠️
... and 39 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #704      +/-   ##
==========================================
- Coverage   62.94%   61.09%   -1.85%     
==========================================
  Files         148      140       -8     
  Lines       12611    11316    -1295     
==========================================
- Hits         7938     6914    -1024     
+ Misses       3835     3629     -206     
+ Partials      838      773      -65     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rowanseymour
rowanseymour merged commit 80ae001 into main Apr 20, 2026
4 checks passed
@rowanseymour
rowanseymour deleted the upmerge-v9.0.1 branch April 20, 2026 21:27
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