trueppm-api 0.4.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trueppm_api/__init__.py +14 -0
- trueppm_api/apps/access/__init__.py +0 -0
- trueppm_api/apps/access/apps.py +19 -0
- trueppm_api/apps/access/groups.py +518 -0
- trueppm_api/apps/access/management/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/create_admin.py +164 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +209 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +167 -0
- trueppm_api/apps/access/migrations/0002_alter_projectmembership_id.py +29 -0
- trueppm_api/apps/access/migrations/0003_projectmembership_soft_delete.py +24 -0
- trueppm_api/apps/access/migrations/0004_alter_projectmembership_role.py +34 -0
- trueppm_api/apps/access/migrations/0005_program_entity_and_membership.py +76 -0
- trueppm_api/apps/access/migrations/0006_role_ordinal_spacing.py +113 -0
- trueppm_api/apps/access/migrations/0007_projectmembership_joined_at_and_more.py +35 -0
- trueppm_api/apps/access/migrations/0008_projectmembership_source_group.py +25 -0
- trueppm_api/apps/access/migrations/0009_projectmembership_pm_proj_serverver_idx.py +20 -0
- trueppm_api/apps/access/migrations/0010_programmembership_joined_at_and_more.py +38 -0
- trueppm_api/apps/access/migrations/0011_alter_programmembership_unique_together_and_more.py +36 -0
- trueppm_api/apps/access/migrations/0012_programmembership_role_title.py +17 -0
- trueppm_api/apps/access/migrations/0013_userdefinedmentiongroup.py +82 -0
- trueppm_api/apps/access/migrations/0014_programmembership_progm_serverver_idx.py +19 -0
- trueppm_api/apps/access/migrations/0015_programuserdefinedmentiongroup.py +86 -0
- trueppm_api/apps/access/migrations/0016_externalstakeholder.py +67 -0
- trueppm_api/apps/access/migrations/0017_viewer_ordinal_one.py +132 -0
- trueppm_api/apps/access/migrations/0018_programmembership_sync_seq_and_more.py +52 -0
- trueppm_api/apps/access/migrations/0019_programmembership_reinstated_at_and_more.py +22 -0
- trueppm_api/apps/access/migrations/__init__.py +0 -0
- trueppm_api/apps/access/models.py +588 -0
- trueppm_api/apps/access/permissions.py +2837 -0
- trueppm_api/apps/access/serializers.py +946 -0
- trueppm_api/apps/access/services.py +667 -0
- trueppm_api/apps/access/signals.py +103 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +95 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1931 -0
- trueppm_api/apps/agents/__init__.py +6 -0
- trueppm_api/apps/agents/apps.py +11 -0
- trueppm_api/apps/agents/canonical.py +73 -0
- trueppm_api/apps/agents/deferred.py +108 -0
- trueppm_api/apps/agents/management/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/audit_prune.py +137 -0
- trueppm_api/apps/agents/management/commands/audit_verify.py +101 -0
- trueppm_api/apps/agents/middleware.py +44 -0
- trueppm_api/apps/agents/migrations/0001_initial.py +231 -0
- trueppm_api/apps/agents/migrations/0002_agentactioncheckpoint.py +71 -0
- trueppm_api/apps/agents/migrations/0003_agentactionrefusaldetail.py +58 -0
- trueppm_api/apps/agents/migrations/__init__.py +0 -0
- trueppm_api/apps/agents/models.py +371 -0
- trueppm_api/apps/agents/refusal.py +103 -0
- trueppm_api/apps/agents/serializers.py +85 -0
- trueppm_api/apps/agents/services.py +397 -0
- trueppm_api/apps/agents/signals.py +30 -0
- trueppm_api/apps/agents/urls.py +15 -0
- trueppm_api/apps/agents/views.py +108 -0
- trueppm_api/apps/csvimport/__init__.py +12 -0
- trueppm_api/apps/csvimport/apps.py +11 -0
- trueppm_api/apps/csvimport/mapping.py +363 -0
- trueppm_api/apps/csvimport/migrations/0001_initial.py +74 -0
- trueppm_api/apps/csvimport/migrations/0002_schedule_outline_batch_operations.py +37 -0
- trueppm_api/apps/csvimport/migrations/0003_csvimportrequest_date_order_and_more.py +26 -0
- trueppm_api/apps/csvimport/migrations/__init__.py +0 -0
- trueppm_api/apps/csvimport/models.py +111 -0
- trueppm_api/apps/csvimport/parser.py +1825 -0
- trueppm_api/apps/csvimport/services.py +48 -0
- trueppm_api/apps/csvimport/tasks.py +418 -0
- trueppm_api/apps/csvimport/template.py +37 -0
- trueppm_api/apps/csvimport/urls.py +50 -0
- trueppm_api/apps/csvimport/views.py +793 -0
- trueppm_api/apps/history/__init__.py +0 -0
- trueppm_api/apps/history/apps.py +12 -0
- trueppm_api/apps/history/changelog.py +359 -0
- trueppm_api/apps/history/diff_policy.py +177 -0
- trueppm_api/apps/history/serializers.py +104 -0
- trueppm_api/apps/history/signals.py +82 -0
- trueppm_api/apps/history/tasks.py +105 -0
- trueppm_api/apps/history/urls.py +38 -0
- trueppm_api/apps/history/views.py +443 -0
- trueppm_api/apps/idempotency/__init__.py +0 -0
- trueppm_api/apps/idempotency/apps.py +11 -0
- trueppm_api/apps/idempotency/migrations/0001_initial.py +71 -0
- trueppm_api/apps/idempotency/migrations/__init__.py +0 -0
- trueppm_api/apps/idempotency/mixins.py +226 -0
- trueppm_api/apps/idempotency/models.py +75 -0
- trueppm_api/apps/idempotency/tasks.py +61 -0
- trueppm_api/apps/integrations/__init__.py +13 -0
- trueppm_api/apps/integrations/apps.py +59 -0
- trueppm_api/apps/integrations/connections.py +806 -0
- trueppm_api/apps/integrations/encryption.py +92 -0
- trueppm_api/apps/integrations/external_sources.py +837 -0
- trueppm_api/apps/integrations/git_automation_services.py +231 -0
- trueppm_api/apps/integrations/git_webhook_auth.py +243 -0
- trueppm_api/apps/integrations/http.py +403 -0
- trueppm_api/apps/integrations/me_work.py +218 -0
- trueppm_api/apps/integrations/migrations/0001_initial.py +64 -0
- trueppm_api/apps/integrations/migrations/0001_squashed_0006_tasklink_description_tasklink_preview_type_and_more.py +187 -0
- trueppm_api/apps/integrations/migrations/0002_tasklink.py +67 -0
- trueppm_api/apps/integrations/migrations/0003_tasklink_tasklink_serverver_idx.py +17 -0
- trueppm_api/apps/integrations/migrations/0004_tasklink_custom_title_tasklink_labels.py +25 -0
- trueppm_api/apps/integrations/migrations/0005_boardautomation.py +56 -0
- trueppm_api/apps/integrations/migrations/0006_tasklink_description_tasklink_preview_type_and_more.py +40 -0
- trueppm_api/apps/integrations/migrations/0007_tasklink_created_at.py +23 -0
- trueppm_api/apps/integrations/migrations/0008_integrationcredential_config_externalworkitem.py +66 -0
- trueppm_api/apps/integrations/migrations/0009_externalsyncrequest_and_more.py +96 -0
- trueppm_api/apps/integrations/migrations/0010_externalworkitem_due_date.py +17 -0
- trueppm_api/apps/integrations/migrations/0011_tasklink_sync_seq_tasklink_tasklink_syncseq_idx.py +22 -0
- trueppm_api/apps/integrations/migrations/0012_boardautomation_last_delivery_at_and_more.py +42 -0
- trueppm_api/apps/integrations/migrations/0013_externalsyncrequest_attempt_count_and_more.py +26 -0
- trueppm_api/apps/integrations/migrations/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +622 -0
- trueppm_api/apps/integrations/notification_channels.py +57 -0
- trueppm_api/apps/integrations/opengraph.py +229 -0
- trueppm_api/apps/integrations/outgoing.py +201 -0
- trueppm_api/apps/integrations/providers.py +519 -0
- trueppm_api/apps/integrations/registry.py +345 -0
- trueppm_api/apps/integrations/serializers.py +453 -0
- trueppm_api/apps/integrations/services.py +171 -0
- trueppm_api/apps/integrations/tasks.py +731 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1106 -0
- trueppm_api/apps/jiraimport/__init__.py +8 -0
- trueppm_api/apps/jiraimport/apps.py +11 -0
- trueppm_api/apps/jiraimport/migrations/0001_initial.py +72 -0
- trueppm_api/apps/jiraimport/migrations/__init__.py +0 -0
- trueppm_api/apps/jiraimport/models.py +70 -0
- trueppm_api/apps/jiraimport/parser.py +350 -0
- trueppm_api/apps/jiraimport/services.py +46 -0
- trueppm_api/apps/jiraimport/tasks.py +277 -0
- trueppm_api/apps/jiraimport/urls.py +15 -0
- trueppm_api/apps/jiraimport/views.py +153 -0
- trueppm_api/apps/msproject/__init__.py +0 -0
- trueppm_api/apps/msproject/apps.py +11 -0
- trueppm_api/apps/msproject/dataclasses.py +153 -0
- trueppm_api/apps/msproject/exporter.py +500 -0
- trueppm_api/apps/msproject/extended_attributes.py +77 -0
- trueppm_api/apps/msproject/importer.py +1095 -0
- trueppm_api/apps/msproject/migrations/0001_import_request.py +77 -0
- trueppm_api/apps/msproject/migrations/0001_squashed_0002_importrequest_creates_project.py +80 -0
- trueppm_api/apps/msproject/migrations/0002_importrequest_creates_project.py +15 -0
- trueppm_api/apps/msproject/migrations/__init__.py +0 -0
- trueppm_api/apps/msproject/models.py +81 -0
- trueppm_api/apps/msproject/parser.py +1231 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +436 -0
- trueppm_api/apps/msproject/urls.py +39 -0
- trueppm_api/apps/msproject/views.py +531 -0
- trueppm_api/apps/notifications/__init__.py +7 -0
- trueppm_api/apps/notifications/apps.py +15 -0
- trueppm_api/apps/notifications/backfill.py +79 -0
- trueppm_api/apps/notifications/categories.py +112 -0
- trueppm_api/apps/notifications/delivery_limits.py +258 -0
- trueppm_api/apps/notifications/digests.py +447 -0
- trueppm_api/apps/notifications/email_backend.py +330 -0
- trueppm_api/apps/notifications/email_health.py +128 -0
- trueppm_api/apps/notifications/migrations/0001_initial.py +207 -0
- trueppm_api/apps/notifications/migrations/0001_squashed_0006_notification_task.py +294 -0
- trueppm_api/apps/notifications/migrations/0002_project_notification_preference.py +67 -0
- trueppm_api/apps/notifications/migrations/0003_projectnotificationpreference_paused.py +17 -0
- trueppm_api/apps/notifications/migrations/0004_clean_unknown_matrix_keys.py +30 -0
- trueppm_api/apps/notifications/migrations/0005_notification_body_notification_event_type_and_more.py +27 -0
- trueppm_api/apps/notifications/migrations/0006_notification_task.py +25 -0
- trueppm_api/apps/notifications/migrations/0007_workspaceemailsettings.py +80 -0
- trueppm_api/apps/notifications/migrations/0008_notification_snoozed_until.py +17 -0
- trueppm_api/apps/notifications/migrations/0009_usernotificationsettings.py +43 -0
- trueppm_api/apps/notifications/migrations/0010_projectnotificationpreference_schema_version.py +20 -0
- trueppm_api/apps/notifications/migrations/0011_usernotificationsettings_digest_hour_and_more.py +96 -0
- trueppm_api/apps/notifications/migrations/__init__.py +0 -0
- trueppm_api/apps/notifications/models.py +1197 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +961 -0
- trueppm_api/apps/notifications/services.py +1451 -0
- trueppm_api/apps/notifications/tasks.py +711 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +904 -0
- trueppm_api/apps/observability/__init__.py +0 -0
- trueppm_api/apps/observability/apps.py +31 -0
- trueppm_api/apps/observability/logging.py +213 -0
- trueppm_api/apps/observability/migrations/0001_initial.py +35 -0
- trueppm_api/apps/observability/migrations/0001_squashed_0003_alter_purgerun_trigger.py +154 -0
- trueppm_api/apps/observability/migrations/0002_purgerun_retentionpolicy_retentionschedule.py +131 -0
- trueppm_api/apps/observability/migrations/0003_alter_purgerun_trigger.py +21 -0
- trueppm_api/apps/observability/migrations/0004_alter_retentionpolicy_key.py +28 -0
- trueppm_api/apps/observability/migrations/__init__.py +0 -0
- trueppm_api/apps/observability/models.py +141 -0
- trueppm_api/apps/observability/otel/__init__.py +45 -0
- trueppm_api/apps/observability/otel/attributes.py +247 -0
- trueppm_api/apps/observability/otel/export_health.py +533 -0
- trueppm_api/apps/observability/otel/instrumentation.py +351 -0
- trueppm_api/apps/observability/otel/metrics.py +551 -0
- trueppm_api/apps/observability/otel/provider.py +511 -0
- trueppm_api/apps/observability/otel/request_attributes.py +204 -0
- trueppm_api/apps/observability/purge_registry.py +124 -0
- trueppm_api/apps/observability/retention.py +139 -0
- trueppm_api/apps/observability/selectors.py +969 -0
- trueppm_api/apps/observability/serializers.py +142 -0
- trueppm_api/apps/observability/services.py +407 -0
- trueppm_api/apps/observability/tasks.py +266 -0
- trueppm_api/apps/observability/urls.py +27 -0
- trueppm_api/apps/observability/views.py +523 -0
- trueppm_api/apps/profiles/__init__.py +0 -0
- trueppm_api/apps/profiles/apps.py +15 -0
- trueppm_api/apps/profiles/constants.py +54 -0
- trueppm_api/apps/profiles/migrations/0001_initial.py +55 -0
- trueppm_api/apps/profiles/migrations/0001_squashed_0004_userprofile_role_context.py +125 -0
- trueppm_api/apps/profiles/migrations/0002_userprofile_hidden_views.py +17 -0
- trueppm_api/apps/profiles/migrations/0003_projectvisit.py +63 -0
- trueppm_api/apps/profiles/migrations/0004_userprofile_role_context.py +26 -0
- trueppm_api/apps/profiles/migrations/0005_userprofile_schedule_in_deliver.py +20 -0
- trueppm_api/apps/profiles/migrations/0006_userprofile_date_format_userprofile_timezone.py +36 -0
- trueppm_api/apps/profiles/migrations/0007_userpin.py +91 -0
- trueppm_api/apps/profiles/migrations/0008_remove_userprofile_schedule_in_deliver.py +71 -0
- trueppm_api/apps/profiles/migrations/0009_auth_user_email_upper_idx.py +81 -0
- trueppm_api/apps/profiles/migrations/__init__.py +0 -0
- trueppm_api/apps/profiles/models.py +276 -0
- trueppm_api/apps/profiles/serializers.py +199 -0
- trueppm_api/apps/profiles/services.py +466 -0
- trueppm_api/apps/profiles/views.py +124 -0
- trueppm_api/apps/projects/__init__.py +0 -0
- trueppm_api/apps/projects/actual_date_rules.py +163 -0
- trueppm_api/apps/projects/amend.py +133 -0
- trueppm_api/apps/projects/apps.py +38 -0
- trueppm_api/apps/projects/asset_feed.py +459 -0
- trueppm_api/apps/projects/asset_views.py +317 -0
- trueppm_api/apps/projects/attachment_policy.py +278 -0
- trueppm_api/apps/projects/authentication.py +449 -0
- trueppm_api/apps/projects/backfill.py +287 -0
- trueppm_api/apps/projects/backlog_services.py +324 -0
- trueppm_api/apps/projects/backlog_views.py +302 -0
- trueppm_api/apps/projects/batch_operation_views.py +264 -0
- trueppm_api/apps/projects/blocker_services.py +510 -0
- trueppm_api/apps/projects/board_activity.py +462 -0
- trueppm_api/apps/projects/board_activity_views.py +186 -0
- trueppm_api/apps/projects/board_lanes.py +134 -0
- trueppm_api/apps/projects/bulk_settings.py +194 -0
- trueppm_api/apps/projects/bundled_templates.py +215 -0
- trueppm_api/apps/projects/calendar_settings.py +180 -0
- trueppm_api/apps/projects/ceremony_views.py +244 -0
- trueppm_api/apps/projects/commit_moment.py +204 -0
- trueppm_api/apps/projects/config_notice.py +1325 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +93 -0
- trueppm_api/apps/projects/decisions_views.py +94 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +353 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4256 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2000 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1825 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1905 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1409 -0
- trueppm_api/apps/projects/guardrail_policy_source.py +269 -0
- trueppm_api/apps/projects/inbound_sync.py +555 -0
- trueppm_api/apps/projects/iteration_label.py +85 -0
- trueppm_api/apps/projects/lifecycle.py +191 -0
- trueppm_api/apps/projects/management/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/backfill_in_progress_status.py +92 -0
- trueppm_api/apps/projects/management/commands/create_demo_share_link.py +368 -0
- trueppm_api/apps/projects/management/commands/export_program.py +50 -0
- trueppm_api/apps/projects/management/commands/import_seed.py +165 -0
- trueppm_api/apps/projects/management/commands/load_sample_project.py +247 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +405 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +178 -0
- trueppm_api/apps/projects/management/commands/shift_sample_dates.py +120 -0
- trueppm_api/apps/projects/mcp_settings.py +305 -0
- trueppm_api/apps/projects/methodology.py +178 -0
- trueppm_api/apps/projects/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5595 -0
- trueppm_api/apps/projects/migrations/0002_alter_uuid_pk_serialize_false.py +57 -0
- trueppm_api/apps/projects/migrations/0003_rename_task_project_index.py +25 -0
- trueppm_api/apps/projects/migrations/0004_soft_delete_and_dependency_versioned.py +70 -0
- trueppm_api/apps/projects/migrations/0005_task_assignee.py +33 -0
- trueppm_api/apps/projects/migrations/0006_task_utilization_index.py +31 -0
- trueppm_api/apps/projects/migrations/0007_task_is_milestone.py +28 -0
- trueppm_api/apps/projects/migrations/0008_baseline.py +119 -0
- trueppm_api/apps/projects/migrations/0009_historicaldependency_historicalproject_and_more.py +210 -0
- trueppm_api/apps/projects/migrations/0010_risk.py +229 -0
- trueppm_api/apps/projects/migrations/0011_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0012_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0013_task_planned_start.py +24 -0
- trueppm_api/apps/projects/migrations/0014_short_hex_ids.py +74 -0
- trueppm_api/apps/projects/migrations/0015_backfill_short_ids.py +48 -0
- trueppm_api/apps/projects/migrations/0016_task_actual_dates.py +42 -0
- trueppm_api/apps/projects/migrations/0017_boardcolumnconfig.py +43 -0
- trueppm_api/apps/projects/migrations/0018_estimation_governance.py +62 -0
- trueppm_api/apps/projects/migrations/0019_backfill_wbs_paths.py +28 -0
- trueppm_api/apps/projects/migrations/0020_task_status_5col.py +65 -0
- trueppm_api/apps/projects/migrations/0021_boardsavedview.py +64 -0
- trueppm_api/apps/projects/migrations/0022_task_status_changed_at_priority_rank.py +35 -0
- trueppm_api/apps/projects/migrations/0023_risk_framework_fields.py +96 -0
- trueppm_api/apps/projects/migrations/0024_riskcomment.py +52 -0
- trueppm_api/apps/projects/migrations/0025_sprint.py +352 -0
- trueppm_api/apps/projects/migrations/0026_project_methodology.py +30 -0
- trueppm_api/apps/projects/migrations/0027_sprint_retro.py +89 -0
- trueppm_api/apps/projects/migrations/0028_normalize_notes_field.py +42 -0
- trueppm_api/apps/projects/migrations/0029_complete_implies_full_progress.py +38 -0
- trueppm_api/apps/projects/migrations/0030_review_implies_full_progress.py +37 -0
- trueppm_api/apps/projects/migrations/0031_task_remaining_points.py +22 -0
- trueppm_api/apps/projects/migrations/0032_task_is_subtask_and_sprint_scope_change.py +90 -0
- trueppm_api/apps/projects/migrations/0033_task_my_work_index.py +38 -0
- trueppm_api/apps/projects/migrations/0034_inbound_task_sync.py +313 -0
- trueppm_api/apps/projects/migrations/0035_retro_versioned_and_suggested_assignee.py +173 -0
- trueppm_api/apps/projects/migrations/0036_program_entity_and_membership.py +157 -0
- trueppm_api/apps/projects/migrations/0037_sprint_capacity_points.py +20 -0
- trueppm_api/apps/projects/migrations/0038_taskcomment_commentreaction_commentacknowledgement_and_more.py +233 -0
- trueppm_api/apps/projects/migrations/0039_apitoken_and_more.py +88 -0
- trueppm_api/apps/projects/migrations/0040_program_general_fields.py +119 -0
- trueppm_api/apps/projects/migrations/0041_ceremony_template_and_phase_gate_config.py +210 -0
- trueppm_api/apps/projects/migrations/0041_project_general_fields.py +106 -0
- trueppm_api/apps/projects/migrations/0042_merge_20260522_0410.py +12 -0
- trueppm_api/apps/projects/migrations/0042_program_rollup_config.py +95 -0
- trueppm_api/apps/projects/migrations/0042_workflow_color_and_custom_fields.py +94 -0
- trueppm_api/apps/projects/migrations/0043_merge_20260522_1118.py +10 -0
- trueppm_api/apps/projects/migrations/0044_merge_20260522_rollup.py +10 -0
- trueppm_api/apps/projects/migrations/0044_project_archive_program_close.py +119 -0
- trueppm_api/apps/projects/migrations/0045_program_risk_policy.py +78 -0
- trueppm_api/apps/projects/migrations/0046_merge_20260523_2248.py +12 -0
- trueppm_api/apps/projects/migrations/0047_apitokenauditentry_program_and_more.py +55 -0
- trueppm_api/apps/projects/migrations/0048_historicalprogram_color_program_color.py +32 -0
- trueppm_api/apps/projects/migrations/0049_backlog_item.py +112 -0
- trueppm_api/apps/projects/migrations/0050_backlog_item_trgm_search.py +26 -0
- trueppm_api/apps/projects/migrations/0051_alter_calendar_working_days_alter_dependency_lag_and_more.py +144 -0
- trueppm_api/apps/projects/migrations/0052_recurring_tasks.py +278 -0
- trueppm_api/apps/projects/migrations/0053_dependency_dep_pred_serverver_idx_and_more.py +56 -0
- trueppm_api/apps/projects/migrations/0054_sprintscopechange_goal_impact_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0055_historicaltask_sprint_pending_and_more.py +51 -0
- trueppm_api/apps/projects/migrations/0056_historicalproject_prioritization_model_and_more.py +276 -0
- trueppm_api/apps/projects/migrations/0057_historicalsprint_binding_committed_snapshot_and_more.py +58 -0
- trueppm_api/apps/projects/migrations/0058_historicaltask_delivery_mode_and_more.py +72 -0
- trueppm_api/apps/projects/migrations/0059_forecastsnapshot.py +80 -0
- trueppm_api/apps/projects/migrations/0060_historicalprojectsignalprivacypolicy_and_more.py +90 -0
- trueppm_api/apps/projects/migrations/0061_baselinetask_story_points.py +17 -0
- trueppm_api/apps/projects/migrations/0062_project_is_sample.py +22 -0
- trueppm_api/apps/projects/migrations/0063_historicalsprint_wip_limit_sprint_wip_limit.py +22 -0
- trueppm_api/apps/projects/migrations/0064_sprinttaskoutcome.py +97 -0
- trueppm_api/apps/projects/migrations/0065_historicalsprint_goal_outcome_sprint_goal_outcome.py +32 -0
- trueppm_api/apps/projects/migrations/0066_historicalproject_lead_project_lead.py +38 -0
- trueppm_api/apps/projects/migrations/0067_sprint_exclude_from_velocity.py +22 -0
- trueppm_api/apps/projects/migrations/0068_project_recalculated_at.py +23 -0
- trueppm_api/apps/projects/migrations/0069_iteration_label.py +22 -0
- trueppm_api/apps/projects/migrations/0070_historicalprogram_iteration_label_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0071_backfill_iteration_label_inherit.py +35 -0
- trueppm_api/apps/projects/migrations/0072_pulseresponse_retroboarditem.py +129 -0
- trueppm_api/apps/projects/migrations/0073_sprinttaskoutcome_demo_ready.py +17 -0
- trueppm_api/apps/projects/migrations/0074_historicaltask_blocked_reason_task_blocked_reason.py +30 -0
- trueppm_api/apps/projects/migrations/0075_risk_decimal_short_id.py +42 -0
- trueppm_api/apps/projects/migrations/0076_sprinttaskoutcome_review_polish.py +45 -0
- trueppm_api/apps/projects/migrations/0077_task_blocker_fields.py +111 -0
- trueppm_api/apps/projects/migrations/0078_alter_risktask_unique_together_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0079_historicalproject_status_date_project_status_date.py +22 -0
- trueppm_api/apps/projects/migrations/0080_alter_historicaltask_type_alter_task_type.py +46 -0
- trueppm_api/apps/projects/migrations/0081_historicalprogram_allow_guests_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0082_project_last_sync_version.py +90 -0
- trueppm_api/apps/projects/migrations/0083_historicalprogram_mc_history_attribution_audience_and_more.py +108 -0
- trueppm_api/apps/projects/migrations/0084_tasknote.py +71 -0
- trueppm_api/apps/projects/migrations/0085_sprint_ix_sprint_velocity.py +33 -0
- trueppm_api/apps/projects/migrations/0086_board_card_search_trgm.py +33 -0
- trueppm_api/apps/projects/migrations/0087_historicalprogram_task_duration_change_percent_policy_and_more.py +155 -0
- trueppm_api/apps/projects/migrations/0088_historicalprogram_allowed_attachment_types_and_more.py +61 -0
- trueppm_api/apps/projects/migrations/0089_signalceilingraiseproposal_signalceilingraisevote_and_more.py +157 -0
- trueppm_api/apps/projects/migrations/0090_historicaltask_proj_histdate_index.py +44 -0
- trueppm_api/apps/projects/migrations/0091_project_board_cadence.py +39 -0
- trueppm_api/apps/projects/migrations/0092_program_target_date.py +22 -0
- trueppm_api/apps/projects/migrations/0093_cross_project_dependency_consent.py +58 -0
- trueppm_api/apps/projects/migrations/0094_project_decisions_policy.py +90 -0
- trueppm_api/apps/projects/migrations/0095_poker_session_vote.py +127 -0
- trueppm_api/apps/projects/migrations/0095_squashed_0097_release_0_3.py +225 -0
- trueppm_api/apps/projects/migrations/0096_crossprojectslipconflict.py +91 -0
- trueppm_api/apps/projects/migrations/0097_backlogitem_backlogitem_tags_gin_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0098_historicalproject_show_baselines_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0099_apitoken_scopes.py +48 -0
- trueppm_api/apps/projects/migrations/0100_task_dep_serverver_idx_concurrent.py +61 -0
- trueppm_api/apps/projects/migrations/0101_dependency_deleted_at_task_deleted_at.py +22 -0
- trueppm_api/apps/projects/migrations/0102_project_deleted_at_project_proj_isdel_deletedat_idx.py +25 -0
- trueppm_api/apps/projects/migrations/0103_taskdurationchangeevent_task_dur_evt_sprint_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0104_historicalproject_stale_task_threshold_days_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0104_trash_restore_1113.py +38 -0
- trueppm_api/apps/projects/migrations/0105_historical_changelog_indexes.py +62 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -0
- trueppm_api/apps/projects/migrations/0107_task_activity_event.py +70 -0
- trueppm_api/apps/projects/migrations/0108_remove_apitoken_api_token_scope_xor_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0109_projectexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0110_sharelink.py +123 -0
- trueppm_api/apps/projects/migrations/0111_projectcalendarlayer.py +67 -0
- trueppm_api/apps/projects/migrations/0112_sharelink_expires_at_alter_sharelink_content_kind.py +31 -0
- trueppm_api/apps/projects/migrations/0113_alter_historicaltask_percent_complete_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0114_historicalproject_default_member_role_and_more.py +28 -0
- trueppm_api/apps/projects/migrations/0115_historicalproject_end_date_shift_threshold_days_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0116_alter_taskactivityevent_event_type.py +28 -0
- trueppm_api/apps/projects/migrations/0117_label_tasklabel_label_tasks_and_more.py +126 -0
- trueppm_api/apps/projects/migrations/0118_programexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0119_historicalprogram_calendar_program_calendar.py +36 -0
- trueppm_api/apps/projects/migrations/0120_alter_backlogitem_item_type.py +29 -0
- trueppm_api/apps/projects/migrations/0121_task_three_point_estimate_ordered.py +64 -0
- trueppm_api/apps/projects/migrations/0122_task_relation.py +173 -0
- trueppm_api/apps/projects/migrations/0123_remove_historicalproject_agile_features_and_more.py +20 -0
- trueppm_api/apps/projects/migrations/0124_dependency_is_driving.py +17 -0
- trueppm_api/apps/projects/migrations/0125_historicalprogram_estimation_scale_and_more.py +68 -0
- trueppm_api/apps/projects/migrations/0126_projectcustomfield_show_on_card_taskcustomfieldvalue.py +80 -0
- trueppm_api/apps/projects/migrations/0127_historicalprogram_mcp_enabled_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0128_acceptancecriterion_sync_seq_apitoken_sync_seq_and_more.py +192 -0
- trueppm_api/apps/projects/migrations/0129_sharelink_show_milestone_dates.py +20 -0
- trueppm_api/apps/projects/migrations/0130_programimportjob.py +85 -0
- trueppm_api/apps/projects/migrations/0131_historicalprogram_sprint_picker_ready_only_default_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0132_task_scheduled_start.py +17 -0
- trueppm_api/apps/projects/migrations/0133_project_status_date_floor_armed_at.py +17 -0
- trueppm_api/apps/projects/migrations/0134_task_edited_at_task_seeded_at_task_source_id_and_more.py +65 -0
- trueppm_api/apps/projects/migrations/0135_projecttemplate_templateapplication_and_more.py +175 -0
- trueppm_api/apps/projects/migrations/0136_schedule_outline_batch_operations.py +118 -0
- trueppm_api/apps/projects/migrations/0137_collapse_dual_scope_api_tokens.py +54 -0
- trueppm_api/apps/projects/migrations/0138_apitokenauditentry_api_token_audit_owner_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0139_historicaltask_duration_unit_task_duration_unit.py +32 -0
- trueppm_api/apps/projects/migrations/0140_historicaltask_auto_container_and_more.py +113 -0
- trueppm_api/apps/projects/migrations/0141_historicalproject_draft_started_at_and_more.py +44 -0
- trueppm_api/apps/projects/migrations/0142_baseline_calendar_hours_per_day_and_more.py +31 -0
- trueppm_api/apps/projects/migrations/0143_sprintcloserequest_failure_reason_and_more.py +42 -0
- trueppm_api/apps/projects/migrations/0144_projecttemplate_source_project_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0145_seed_bundled_templates.py +65 -0
- trueppm_api/apps/projects/migrations/0146_historicaltask_board_lane_task_board_lane.py +32 -0
- trueppm_api/apps/projects/migrations/0147_structuraloperation.py +128 -0
- trueppm_api/apps/projects/migrations/0148_task_unique_task_wbs_path_per_project_live.py +76 -0
- trueppm_api/apps/projects/migrations/0149_drop_workshops_tables.py +42 -0
- trueppm_api/apps/projects/migrations/0150_clear_uncommitted_cpm_output.py +130 -0
- trueppm_api/apps/projects/migrations/0151_config_notice_request.py +70 -0
- trueppm_api/apps/projects/migrations/0152_aggregate_task_wbs_name_idx.py +20 -0
- trueppm_api/apps/projects/migrations/0153_program_sample_anchor_date.py +22 -0
- trueppm_api/apps/projects/migrations/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +8946 -0
- trueppm_api/apps/projects/poker_services.py +154 -0
- trueppm_api/apps/projects/poker_views.py +398 -0
- trueppm_api/apps/projects/product_backlog_services.py +450 -0
- trueppm_api/apps/projects/program_label_services.py +94 -0
- trueppm_api/apps/projects/program_label_views.py +189 -0
- trueppm_api/apps/projects/program_rollup.py +575 -0
- trueppm_api/apps/projects/program_schedule.py +745 -0
- trueppm_api/apps/projects/program_views.py +3220 -0
- trueppm_api/apps/projects/project_templates.py +422 -0
- trueppm_api/apps/projects/receivers.py +234 -0
- trueppm_api/apps/projects/refusal_codes.py +140 -0
- trueppm_api/apps/projects/reorder_services.py +145 -0
- trueppm_api/apps/projects/restructure_hooks.py +54 -0
- trueppm_api/apps/projects/retro_board_services.py +368 -0
- trueppm_api/apps/projects/retro_services.py +285 -0
- trueppm_api/apps/projects/risk_import.py +396 -0
- trueppm_api/apps/projects/row_identity.py +113 -0
- trueppm_api/apps/projects/schema_migrations.py +228 -0
- trueppm_api/apps/projects/schemas/seed_v1.json +493 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +892 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/exporter.py +1644 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2390 -0
- trueppm_api/apps/projects/seed/reanchor.py +551 -0
- trueppm_api/apps/projects/seed/reldates.py +126 -0
- trueppm_api/apps/projects/seed/replace.py +126 -0
- trueppm_api/apps/projects/seed/replay.py +1691 -0
- trueppm_api/apps/projects/seed/replay_ctx.py +41 -0
- trueppm_api/apps/projects/seed/samples.py +427 -0
- trueppm_api/apps/projects/seed/validation.py +1149 -0
- trueppm_api/apps/projects/serializers.py +12310 -0
- trueppm_api/apps/projects/services.py +6966 -0
- trueppm_api/apps/projects/share_serializers.py +132 -0
- trueppm_api/apps/projects/share_services.py +325 -0
- trueppm_api/apps/projects/share_views.py +374 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +909 -0
- trueppm_api/apps/projects/signal_privacy_views.py +476 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +266 -0
- trueppm_api/apps/projects/sprint_cadence.py +453 -0
- trueppm_api/apps/projects/sprint_picker_settings.py +132 -0
- trueppm_api/apps/projects/standup.py +304 -0
- trueppm_api/apps/projects/standup_views.py +99 -0
- trueppm_api/apps/projects/structural_operation_services.py +727 -0
- trueppm_api/apps/projects/structural_operation_views.py +311 -0
- trueppm_api/apps/projects/surface_visibility.py +126 -0
- trueppm_api/apps/projects/task_batch_services.py +379 -0
- trueppm_api/apps/projects/task_bulk.py +1152 -0
- trueppm_api/apps/projects/task_classification.py +561 -0
- trueppm_api/apps/projects/task_classification_defaults.py +95 -0
- trueppm_api/apps/projects/task_duration_settings.py +142 -0
- trueppm_api/apps/projects/task_grouping.py +754 -0
- trueppm_api/apps/projects/tasks.py +1917 -0
- trueppm_api/apps/projects/template_divergence.py +168 -0
- trueppm_api/apps/projects/template_services.py +160 -0
- trueppm_api/apps/projects/template_tasks.py +258 -0
- trueppm_api/apps/projects/template_views.py +799 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1011 -0
- trueppm_api/apps/projects/utilization.py +885 -0
- trueppm_api/apps/projects/views.py +20572 -0
- trueppm_api/apps/projects/wbs_paths.py +119 -0
- trueppm_api/apps/resources/__init__.py +0 -0
- trueppm_api/apps/resources/apps.py +8 -0
- trueppm_api/apps/resources/capacity.py +121 -0
- trueppm_api/apps/resources/migrations/0001_initial.py +68 -0
- trueppm_api/apps/resources/migrations/0001_squashed_0013_alter_projectresource_unique_together_and_more.py +281 -0
- trueppm_api/apps/resources/migrations/0002_alter_uuid_pk_serialize_false.py +36 -0
- trueppm_api/apps/resources/migrations/0003_resource_soft_delete.py +30 -0
- trueppm_api/apps/resources/migrations/0004_add_taskresource_resource_index.py +25 -0
- trueppm_api/apps/resources/migrations/0005_resource_job_role.py +20 -0
- trueppm_api/apps/resources/migrations/0006_skill.py +34 -0
- trueppm_api/apps/resources/migrations/0007_resource_skill.py +63 -0
- trueppm_api/apps/resources/migrations/0008_project_resource.py +63 -0
- trueppm_api/apps/resources/migrations/0009_task_skill_requirement.py +60 -0
- trueppm_api/apps/resources/migrations/0010_alter_resourceskill_options_and_more.py +20 -0
- trueppm_api/apps/resources/migrations/0011_alter_projectresource_notes.py +17 -0
- trueppm_api/apps/resources/migrations/0012_add_resource_user_fk.py +26 -0
- trueppm_api/apps/resources/migrations/0013_alter_projectresource_unique_together_and_more.py +53 -0
- trueppm_api/apps/resources/migrations/0014_projectresource_sync_seq_resource_sync_seq_and_more.py +37 -0
- trueppm_api/apps/resources/migrations/0015_projectresource_deactivated_with_resource.py +17 -0
- trueppm_api/apps/resources/migrations/__init__.py +0 -0
- trueppm_api/apps/resources/models.py +298 -0
- trueppm_api/apps/resources/serializers.py +426 -0
- trueppm_api/apps/resources/services.py +465 -0
- trueppm_api/apps/resources/urls.py +28 -0
- trueppm_api/apps/resources/views.py +1749 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +119 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -0
- trueppm_api/apps/scheduling/forecast_history_settings.py +215 -0
- trueppm_api/apps/scheduling/forecast_staleness.py +313 -0
- trueppm_api/apps/scheduling/graph_guard.py +263 -0
- trueppm_api/apps/scheduling/management/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/prune_forecast_snapshots.py +53 -0
- trueppm_api/apps/scheduling/migrations/0001_failed_task.py +62 -0
- trueppm_api/apps/scheduling/migrations/0001_squashed_0007_projectforecastsnapshot.py +309 -0
- trueppm_api/apps/scheduling/migrations/0002_schedulerequest.py +78 -0
- trueppm_api/apps/scheduling/migrations/0003_add_schedule_request_reason.py +27 -0
- trueppm_api/apps/scheduling/migrations/0004_velocity_suggestion.py +94 -0
- trueppm_api/apps/scheduling/migrations/0005_montecarlorun.py +61 -0
- trueppm_api/apps/scheduling/migrations/0006_montecarlorun_distribution.py +17 -0
- trueppm_api/apps/scheduling/migrations/0007_projectforecastsnapshot.py +65 -0
- trueppm_api/apps/scheduling/migrations/0008_alter_schedulerequest_reason.py +28 -0
- trueppm_api/apps/scheduling/migrations/0008_folded_schedulerequest_reason.py +34 -0
- trueppm_api/apps/scheduling/migrations/0009_alter_schedulerequest_reason.py +29 -0
- trueppm_api/apps/scheduling/migrations/0010_failedtask_resolution_note_failedtask_resolved_at_and_more.py +43 -0
- trueppm_api/apps/scheduling/migrations/0011_failedtask_project.py +26 -0
- trueppm_api/apps/scheduling/migrations/0012_montecarlorun_diagnostic.py +17 -0
- trueppm_api/apps/scheduling/migrations/0013_montecarlorun_status_date.py +17 -0
- trueppm_api/apps/scheduling/migrations/0014_montecarlorun_plan_version.py +17 -0
- trueppm_api/apps/scheduling/migrations/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +516 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +283 -0
- trueppm_api/apps/scheduling/serializers.py +564 -0
- trueppm_api/apps/scheduling/services.py +1182 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +1984 -0
- trueppm_api/apps/scheduling/telemetry.py +80 -0
- trueppm_api/apps/scheduling/units.py +35 -0
- trueppm_api/apps/scheduling/urls.py +57 -0
- trueppm_api/apps/scheduling/views.py +2564 -0
- trueppm_api/apps/sso/__init__.py +0 -0
- trueppm_api/apps/sso/apps.py +19 -0
- trueppm_api/apps/sso/extensions.py +130 -0
- trueppm_api/apps/sso/management/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/seed_sso_keycloak.py +172 -0
- trueppm_api/apps/sso/migrations/0001_initial.py +119 -0
- trueppm_api/apps/sso/migrations/0002_remove_oidcprovider_workspace_ssoproviderpolicy_and_more.py +169 -0
- trueppm_api/apps/sso/migrations/__init__.py +0 -0
- trueppm_api/apps/sso/models.py +148 -0
- trueppm_api/apps/sso/serializers.py +437 -0
- trueppm_api/apps/sso/services.py +1385 -0
- trueppm_api/apps/sso/urls.py +47 -0
- trueppm_api/apps/sso/views.py +935 -0
- trueppm_api/apps/sync/__init__.py +0 -0
- trueppm_api/apps/sync/apps.py +15 -0
- trueppm_api/apps/sync/backfill.py +208 -0
- trueppm_api/apps/sync/broadcast.py +320 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +471 -0
- trueppm_api/apps/sync/migrations/0001_initial.py +59 -0
- trueppm_api/apps/sync/migrations/0001_squashed_0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +77 -0
- trueppm_api/apps/sync/migrations/0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +41 -0
- trueppm_api/apps/sync/migrations/0003_boardevent.py +46 -0
- trueppm_api/apps/sync/migrations/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +225 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +371 -0
- trueppm_api/apps/sync/serializers.py +687 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +501 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +930 -0
- trueppm_api/apps/sync/ws_auth.py +193 -0
- trueppm_api/apps/taskruns/__init__.py +0 -0
- trueppm_api/apps/taskruns/apps.py +11 -0
- trueppm_api/apps/taskruns/migrations/0001_initial.py +92 -0
- trueppm_api/apps/taskruns/migrations/__init__.py +0 -0
- trueppm_api/apps/taskruns/models.py +68 -0
- trueppm_api/apps/taskruns/serializers.py +92 -0
- trueppm_api/apps/taskruns/tasks.py +60 -0
- trueppm_api/apps/taskruns/tracker.py +286 -0
- trueppm_api/apps/taskruns/urls.py +46 -0
- trueppm_api/apps/taskruns/views.py +195 -0
- trueppm_api/apps/teams/__init__.py +8 -0
- trueppm_api/apps/teams/apps.py +16 -0
- trueppm_api/apps/teams/migrations/0001_initial.py +139 -0
- trueppm_api/apps/teams/migrations/0001_squashed_0002_default_teams.py +142 -0
- trueppm_api/apps/teams/migrations/0002_default_teams.py +62 -0
- trueppm_api/apps/teams/migrations/0003_team_sync_seq_teammembership_sync_seq.py +22 -0
- trueppm_api/apps/teams/migrations/__init__.py +0 -0
- trueppm_api/apps/teams/models.py +145 -0
- trueppm_api/apps/teams/permissions.py +149 -0
- trueppm_api/apps/teams/serializers.py +95 -0
- trueppm_api/apps/teams/services.py +434 -0
- trueppm_api/apps/teams/signals.py +61 -0
- trueppm_api/apps/teams/urls.py +34 -0
- trueppm_api/apps/teams/views.py +201 -0
- trueppm_api/apps/timetracking/__init__.py +0 -0
- trueppm_api/apps/timetracking/apps.py +9 -0
- trueppm_api/apps/timetracking/migrations/0001_initial.py +117 -0
- trueppm_api/apps/timetracking/migrations/0002_timesheetsubmission.py +46 -0
- trueppm_api/apps/timetracking/migrations/0003_timeentry_deleted_at_timeentry_deleted_by.py +31 -0
- trueppm_api/apps/timetracking/migrations/0004_timeentry_sync_seq_and_more.py +24 -0
- trueppm_api/apps/timetracking/migrations/__init__.py +0 -0
- trueppm_api/apps/timetracking/models.py +178 -0
- trueppm_api/apps/timetracking/serializers.py +175 -0
- trueppm_api/apps/timetracking/services.py +117 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +526 -0
- trueppm_api/apps/webhooks/__init__.py +0 -0
- trueppm_api/apps/webhooks/apps.py +8 -0
- trueppm_api/apps/webhooks/backfill.py +90 -0
- trueppm_api/apps/webhooks/dispatch.py +144 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +243 -0
- trueppm_api/apps/webhooks/migrations/0002_alter_webhook_events.py +32 -0
- trueppm_api/apps/webhooks/migrations/0003_delivery_status_created_idx.py +17 -0
- trueppm_api/apps/webhooks/migrations/0004_webhook_program_alter_webhook_project_and_more.py +64 -0
- trueppm_api/apps/webhooks/migrations/0005_webhook_delivery_sequence_numbers.py +30 -0
- trueppm_api/apps/webhooks/migrations/0006_webhook_format_alter_webhook_events_and_more.py +61 -0
- trueppm_api/apps/webhooks/migrations/0007_sprint_lifecycle_events.py +63 -0
- trueppm_api/apps/webhooks/migrations/0008_risk_baseline_comment_events.py +73 -0
- trueppm_api/apps/webhooks/migrations/0009_encrypt_webhook_secret_and_failure_counters.py +90 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +372 -0
- trueppm_api/apps/webhooks/serializers.py +318 -0
- trueppm_api/apps/webhooks/tasks.py +663 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +383 -0
- trueppm_api/apps/workflow_engine/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/apps.py +23 -0
- trueppm_api/apps/workflow_engine/migrations/0001_initial.py +230 -0
- trueppm_api/apps/workflow_engine/migrations/0001_squashed_0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +234 -0
- trueppm_api/apps/workflow_engine/migrations/0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +16 -0
- trueppm_api/apps/workflow_engine/migrations/0003_workflowoutboxrow_workflow_outbox_recovery_idx.py +21 -0
- trueppm_api/apps/workflow_engine/migrations/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/models.py +265 -0
- trueppm_api/apps/workflow_engine/tasks.py +368 -0
- trueppm_api/apps/workspace/__init__.py +0 -0
- trueppm_api/apps/workspace/apps.py +10 -0
- trueppm_api/apps/workspace/backfill.py +111 -0
- trueppm_api/apps/workspace/export.py +242 -0
- trueppm_api/apps/workspace/migrations/0001_initial.py +326 -0
- trueppm_api/apps/workspace/migrations/0001_squashed_0014_workspacemembership_availability_effective_from_and_more.py +829 -0
- trueppm_api/apps/workspace/migrations/0002_remove_workspace_fiscal_year_start_and_more.py +85 -0
- trueppm_api/apps/workspace/migrations/0003_workspaceexportjob.py +73 -0
- trueppm_api/apps/workspace/migrations/0004_alter_workspaceinvite_status.py +27 -0
- trueppm_api/apps/workspace/migrations/0005_workspace_iteration_label_and_more.py +26 -0
- trueppm_api/apps/workspace/migrations/0006_alter_groupmembership_unique_together_and_more.py +45 -0
- trueppm_api/apps/workspace/migrations/0007_workspace_public_sharing_override_policy.py +21 -0
- trueppm_api/apps/workspace/migrations/0008_workspace_mc_history_attribution_audience_and_more.py +44 -0
- trueppm_api/apps/workspace/migrations/0009_workspace_methodology_and_more.py +186 -0
- trueppm_api/apps/workspace/migrations/0010_workspace_logo.py +38 -0
- trueppm_api/apps/workspace/migrations/0011_historicalworkspace_task_duration_change_percent_override_policy_and_more.py +56 -0
- trueppm_api/apps/workspace/migrations/0012_historicalworkspace_allowed_attachment_types_and_more.py +64 -0
- trueppm_api/apps/workspace/migrations/0013_auditevent.py +70 -0
- trueppm_api/apps/workspace/migrations/0014_workspacemembership_availability_effective_from_and_more.py +39 -0
- trueppm_api/apps/workspace/migrations/0015_trash_restore_1113.py +34 -0
- trueppm_api/apps/workspace/migrations/0016_historicalworkspace_calendar_and_more.py +55 -0
- trueppm_api/apps/workspace/migrations/0017_historicalworkspace_estimation_scale_and_more.py +38 -0
- trueppm_api/apps/workspace/migrations/0018_historicalworkspace_feedback_enabled_and_more.py +32 -0
- trueppm_api/apps/workspace/migrations/0019_historicalworkspace_mcp_enabled_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0020_viewer_ordinal_one.py +34 -0
- trueppm_api/apps/workspace/migrations/0021_group_sync_seq_groupmembership_sync_seq_and_more.py +27 -0
- trueppm_api/apps/workspace/migrations/0022_historicalworkspace_sprint_picker_ready_only_default_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0023_alter_auditevent_event_type.py +32 -0
- trueppm_api/apps/workspace/migrations/0024_alter_auditevent_event_type.py +33 -0
- trueppm_api/apps/workspace/migrations/0025_alter_auditevent_event_type.py +36 -0
- trueppm_api/apps/workspace/migrations/0026_alter_auditevent_event_type.py +37 -0
- trueppm_api/apps/workspace/migrations/0027_alter_auditevent_event_type.py +42 -0
- trueppm_api/apps/workspace/migrations/__init__.py +0 -0
- trueppm_api/apps/workspace/models.py +857 -0
- trueppm_api/apps/workspace/permissions.py +187 -0
- trueppm_api/apps/workspace/serializers.py +590 -0
- trueppm_api/apps/workspace/services.py +919 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +555 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1502 -0
- trueppm_api/asgi.py +42 -0
- trueppm_api/celery.py +31 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +916 -0
- trueppm_api/core/constant_time.py +51 -0
- trueppm_api/core/csp.py +54 -0
- trueppm_api/core/db.py +87 -0
- trueppm_api/core/db_session.py +37 -0
- trueppm_api/core/exception_handlers.py +157 -0
- trueppm_api/core/export_downloads.py +56 -0
- trueppm_api/core/extension_providers.py +56 -0
- trueppm_api/core/extension_signals.py +147 -0
- trueppm_api/core/idempotent.py +260 -0
- trueppm_api/core/metadata.py +42 -0
- trueppm_api/core/middleware.py +51 -0
- trueppm_api/core/openapi.py +949 -0
- trueppm_api/core/password_reset.py +500 -0
- trueppm_api/core/protect_conflict.py +100 -0
- trueppm_api/core/ratelimit.py +148 -0
- trueppm_api/core/redis_throttle.py +82 -0
- trueppm_api/core/refresh_cookie_policy.py +156 -0
- trueppm_api/core/request_body.py +86 -0
- trueppm_api/core/security_checks.py +884 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +344 -0
- trueppm_api/core/valkey.py +214 -0
- trueppm_api/core/valkey_cache.py +66 -0
- trueppm_api/core/valkey_checks.py +104 -0
- trueppm_api/core/valkey_config.py +39 -0
- trueppm_api/core/worker_broker_wait.py +149 -0
- trueppm_api/core/worker_heartbeat.py +134 -0
- trueppm_api/fields.py +36 -0
- trueppm_api/permissions.py +30 -0
- trueppm_api/py.typed +0 -0
- trueppm_api/routing.py +11 -0
- trueppm_api/settings/__init__.py +0 -0
- trueppm_api/settings/base.py +2455 -0
- trueppm_api/settings/dev.py +273 -0
- trueppm_api/settings/prod.py +228 -0
- trueppm_api/urls.py +153 -0
- trueppm_api/workflows/__init__.py +38 -0
- trueppm_api/workflows/backends/__init__.py +6 -0
- trueppm_api/workflows/backends/default.py +297 -0
- trueppm_api/workflows/consumers/__init__.py +11 -0
- trueppm_api/workflows/consumers/requeue_failed_task.py +65 -0
- trueppm_api/workflows/interface.py +148 -0
- trueppm_api/workflows/registry.py +106 -0
- trueppm_api/workflows/services.py +90 -0
- trueppm_api/wsgi.py +11 -0
- trueppm_api-0.4.0b2.dist-info/METADATA +70 -0
- trueppm_api-0.4.0b2.dist-info/RECORD +759 -0
- trueppm_api-0.4.0b2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
"""OpenTelemetry provider bootstrap and enterprise extension point (ADR-0223).
|
|
2
|
+
|
|
3
|
+
This module is the OSS **foundation** for OpenTelemetry (epic #707, issue #708).
|
|
4
|
+
It does not instrument any business logic — that is Phase 1/2. It provides:
|
|
5
|
+
|
|
6
|
+
1. :func:`bootstrap` — called once from ``ObservabilityConfig.ready()``. It reads
|
|
7
|
+
the opt-in configuration and, only when an OTLP endpoint is configured, builds
|
|
8
|
+
a ``TracerProvider`` / ``MeterProvider`` with an OTLP exporter and installs them
|
|
9
|
+
as the process-global providers. With no endpoint it is a **strict no-op**: it
|
|
10
|
+
installs no SDK provider at all, leaving the OTel API's default no-op provider
|
|
11
|
+
in place (no export threads, no per-request cost).
|
|
12
|
+
|
|
13
|
+
2. :func:`register_provider_hook` — the stable extension point the proprietary
|
|
14
|
+
``trueppm-enterprise`` edition registers against to attach its own span
|
|
15
|
+
processors, exporters, or instrumentation, **without importing OSS internals**
|
|
16
|
+
and without OSS importing enterprise (Apache-2.0 boundary rule #3).
|
|
17
|
+
|
|
18
|
+
3. :func:`get_tracer` / :func:`get_meter` — thin, stable accessors over the
|
|
19
|
+
standard OTel API so OSS Phase 1/2 code and enterprise obtain instruments
|
|
20
|
+
through one documented surface. They behave identically in the enabled and
|
|
21
|
+
no-op states.
|
|
22
|
+
|
|
23
|
+
Ordering guarantee: Django fires each ``AppConfig.ready()`` in ``INSTALLED_APPS``
|
|
24
|
+
order, and enterprise apps are appended after OSS apps — so an enterprise hook
|
|
25
|
+
would otherwise register *after* this bootstrap already ran. Registration is
|
|
26
|
+
therefore made order-independent: :func:`bootstrap` invokes every hook already
|
|
27
|
+
registered and stores the resulting context, and :func:`register_provider_hook`
|
|
28
|
+
invokes a late-arriving hook immediately against that stored context. Either
|
|
29
|
+
ordering delivers the context to each hook exactly once.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import logging
|
|
35
|
+
from collections.abc import Callable
|
|
36
|
+
from dataclasses import dataclass
|
|
37
|
+
from importlib import metadata
|
|
38
|
+
from typing import TYPE_CHECKING, Any
|
|
39
|
+
|
|
40
|
+
from django.conf import settings
|
|
41
|
+
from opentelemetry import metrics as otel_metrics
|
|
42
|
+
from opentelemetry import trace as otel_trace
|
|
43
|
+
|
|
44
|
+
from . import attributes
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
48
|
+
from opentelemetry.sdk.resources import Resource
|
|
49
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
50
|
+
from opentelemetry.sdk.trace.sampling import Sampler
|
|
51
|
+
|
|
52
|
+
logger = logging.getLogger(__name__)
|
|
53
|
+
|
|
54
|
+
# The current version of the OTelBootstrapContext contract. Bumped only when a
|
|
55
|
+
# field is ADDED (never renamed/removed) so enterprise can feature-detect.
|
|
56
|
+
_CONTEXT_SCHEMA_VERSION = 1
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True)
|
|
60
|
+
class OTelBootstrapContext:
|
|
61
|
+
"""Immutable snapshot handed to every registered provider hook (ADR-0223 §4).
|
|
62
|
+
|
|
63
|
+
Frozen and carrying an additive ``schema_version``, so it is a stable
|
|
64
|
+
cross-repo contract: new fields are appended, existing fields are never
|
|
65
|
+
renamed or removed. A hook typically does
|
|
66
|
+
``ctx.tracer_provider.add_span_processor(...)`` to attach its own exporter,
|
|
67
|
+
or short-circuits when ``ctx.enabled`` is ``False``.
|
|
68
|
+
|
|
69
|
+
Attributes:
|
|
70
|
+
schema_version: Contract version; enterprise can gate on this.
|
|
71
|
+
enabled: Whether telemetry export is active. When ``False`` the provider
|
|
72
|
+
fields are ``None`` and no SDK provider was installed.
|
|
73
|
+
edition: The value of ``settings.TRUEPPM_EDITION`` (``community`` |
|
|
74
|
+
``enterprise``), also recorded as the ``trueppm.edition`` resource
|
|
75
|
+
attribute.
|
|
76
|
+
resource: The OTel ``Resource`` describing this process, or ``None`` when
|
|
77
|
+
disabled.
|
|
78
|
+
tracer_provider: The installed ``TracerProvider``, or ``None`` when traces
|
|
79
|
+
are disabled.
|
|
80
|
+
meter_provider: The installed ``MeterProvider``, or ``None`` when metrics
|
|
81
|
+
are disabled.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
schema_version: int
|
|
85
|
+
enabled: bool
|
|
86
|
+
edition: str
|
|
87
|
+
resource: Resource | None
|
|
88
|
+
tracer_provider: TracerProvider | None
|
|
89
|
+
meter_provider: MeterProvider | None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
ProviderHook = Callable[[OTelBootstrapContext], None]
|
|
93
|
+
|
|
94
|
+
# Module-level registry. `_context` is set once bootstrap runs; a hook registered
|
|
95
|
+
# after that point is invoked immediately against it (see register_provider_hook).
|
|
96
|
+
_hooks: list[ProviderHook] = []
|
|
97
|
+
_context: OTelBootstrapContext | None = None
|
|
98
|
+
_bootstrapped = False
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def register_provider_hook(hook: ProviderHook) -> None:
|
|
102
|
+
"""Register a callback invoked with the OTel bootstrap context (ADR-0223 §4).
|
|
103
|
+
|
|
104
|
+
This is the enterprise extension point. Enterprise calls it from its own
|
|
105
|
+
``AppConfig.ready()``; the callback receives an :class:`OTelBootstrapContext`
|
|
106
|
+
and may attach additional span processors / exporters or wire instrumentation.
|
|
107
|
+
|
|
108
|
+
Order-independent: if :func:`bootstrap` has already run, ``hook`` is invoked
|
|
109
|
+
immediately with the stored context; otherwise it is invoked when
|
|
110
|
+
:func:`bootstrap` runs. Either way the hook fires exactly once. A hook that
|
|
111
|
+
raises is logged and swallowed so it can never crash app startup.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
hook: A callable taking the :class:`OTelBootstrapContext`.
|
|
115
|
+
"""
|
|
116
|
+
_hooks.append(hook)
|
|
117
|
+
if _context is not None:
|
|
118
|
+
_invoke_hook(hook, _context)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _invoke_hook(hook: ProviderHook, context: OTelBootstrapContext) -> None:
|
|
122
|
+
"""Invoke a single hook, isolating failures from app startup."""
|
|
123
|
+
try:
|
|
124
|
+
hook(context)
|
|
125
|
+
except Exception:
|
|
126
|
+
logger.exception("OpenTelemetry provider hook %r failed", hook)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def is_enabled() -> bool:
|
|
130
|
+
"""Return whether telemetry export is active.
|
|
131
|
+
|
|
132
|
+
Telemetry is on only when the master switch is set AND an OTLP endpoint is
|
|
133
|
+
configured — there is no default endpoint, so the out-of-the-box state is off.
|
|
134
|
+
"""
|
|
135
|
+
endpoint = str(getattr(settings, "OTEL_EXPORTER_OTLP_ENDPOINT", "") or "").strip()
|
|
136
|
+
master = bool(getattr(settings, "TRUEPPM_OTEL_ENABLED", True))
|
|
137
|
+
return master and bool(endpoint)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_tracer(name: str) -> otel_trace.Tracer:
|
|
141
|
+
"""Return an OTel tracer via the standard API (works in the no-op state)."""
|
|
142
|
+
return otel_trace.get_tracer(name)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_meter(name: str) -> otel_metrics.Meter:
|
|
146
|
+
"""Return an OTel meter via the standard API (works in the no-op state)."""
|
|
147
|
+
return otel_metrics.get_meter(name)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def bootstrap() -> OTelBootstrapContext:
|
|
151
|
+
"""Initialize the OTel providers once, then invoke registered hooks.
|
|
152
|
+
|
|
153
|
+
Idempotent: a second call returns the existing context without building a
|
|
154
|
+
second export pipeline (safe under the test runner and the autoreloader).
|
|
155
|
+
|
|
156
|
+
When telemetry is disabled this installs **no** SDK provider — the OTel API
|
|
157
|
+
default no-op provider stays in place — and returns a context with
|
|
158
|
+
``enabled=False``. When enabled it builds the resource, the requested
|
|
159
|
+
providers with an OTLP exporter, sets them global, and returns the context.
|
|
160
|
+
In both cases every registered hook is invoked exactly once.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
The :class:`OTelBootstrapContext` describing the installed state.
|
|
164
|
+
"""
|
|
165
|
+
global _context, _bootstrapped
|
|
166
|
+
|
|
167
|
+
if _bootstrapped and _context is not None:
|
|
168
|
+
return _context
|
|
169
|
+
|
|
170
|
+
edition = str(getattr(settings, "TRUEPPM_EDITION", "community"))
|
|
171
|
+
|
|
172
|
+
if not is_enabled():
|
|
173
|
+
context = OTelBootstrapContext(
|
|
174
|
+
schema_version=_CONTEXT_SCHEMA_VERSION,
|
|
175
|
+
enabled=False,
|
|
176
|
+
edition=edition,
|
|
177
|
+
resource=None,
|
|
178
|
+
tracer_provider=None,
|
|
179
|
+
meter_provider=None,
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
context = _bootstrap_enabled(edition)
|
|
183
|
+
|
|
184
|
+
_context = context
|
|
185
|
+
_bootstrapped = True
|
|
186
|
+
for hook in list(_hooks):
|
|
187
|
+
_invoke_hook(hook, context)
|
|
188
|
+
return context
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _bootstrap_enabled(edition: str) -> OTelBootstrapContext:
|
|
192
|
+
"""Build and install the SDK providers. Falls back to a disabled context on
|
|
193
|
+
any construction error so a misconfiguration can never crash startup."""
|
|
194
|
+
try:
|
|
195
|
+
resource = _build_resource(edition)
|
|
196
|
+
tracer_provider = (
|
|
197
|
+
_build_tracer_provider(resource)
|
|
198
|
+
if getattr(settings, "TRUEPPM_OTEL_TRACES_ENABLED", True)
|
|
199
|
+
else None
|
|
200
|
+
)
|
|
201
|
+
meter_provider = (
|
|
202
|
+
_build_meter_provider(resource)
|
|
203
|
+
if getattr(settings, "TRUEPPM_OTEL_METRICS_ENABLED", True)
|
|
204
|
+
else None
|
|
205
|
+
)
|
|
206
|
+
except Exception:
|
|
207
|
+
logger.exception("OpenTelemetry bootstrap failed; continuing without telemetry export")
|
|
208
|
+
return OTelBootstrapContext(
|
|
209
|
+
schema_version=_CONTEXT_SCHEMA_VERSION,
|
|
210
|
+
enabled=False,
|
|
211
|
+
edition=edition,
|
|
212
|
+
resource=None,
|
|
213
|
+
tracer_provider=None,
|
|
214
|
+
meter_provider=None,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if tracer_provider is not None:
|
|
218
|
+
otel_trace.set_tracer_provider(tracer_provider)
|
|
219
|
+
if meter_provider is not None:
|
|
220
|
+
otel_metrics.set_meter_provider(meter_provider)
|
|
221
|
+
|
|
222
|
+
logger.info(
|
|
223
|
+
"OpenTelemetry enabled: endpoint=%s protocol=%s traces=%s metrics=%s",
|
|
224
|
+
settings.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
225
|
+
settings.OTEL_EXPORTER_OTLP_PROTOCOL,
|
|
226
|
+
tracer_provider is not None,
|
|
227
|
+
meter_provider is not None,
|
|
228
|
+
)
|
|
229
|
+
return OTelBootstrapContext(
|
|
230
|
+
schema_version=_CONTEXT_SCHEMA_VERSION,
|
|
231
|
+
enabled=True,
|
|
232
|
+
edition=edition,
|
|
233
|
+
resource=resource,
|
|
234
|
+
tracer_provider=tracer_provider,
|
|
235
|
+
meter_provider=meter_provider,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _service_version() -> str:
|
|
240
|
+
"""Best-effort ``service.version`` from the installed package metadata."""
|
|
241
|
+
try:
|
|
242
|
+
return metadata.version("trueppm-api")
|
|
243
|
+
except metadata.PackageNotFoundError:
|
|
244
|
+
return "unknown"
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def service_version() -> str:
|
|
248
|
+
"""Public accessor for the resource ``service.version`` (#2110 selector)."""
|
|
249
|
+
return _service_version()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _build_resource(edition: str) -> Resource:
|
|
253
|
+
"""Build the OTel ``Resource`` (service identity + ``trueppm.edition``)."""
|
|
254
|
+
from opentelemetry.sdk.resources import Resource
|
|
255
|
+
|
|
256
|
+
return Resource.create(
|
|
257
|
+
{
|
|
258
|
+
attributes.RESOURCE_SERVICE_NAME: settings.OTEL_SERVICE_NAME,
|
|
259
|
+
attributes.RESOURCE_SERVICE_VERSION: _service_version(),
|
|
260
|
+
attributes.RESOURCE_SERVICE_NAMESPACE: attributes.NAMESPACE,
|
|
261
|
+
attributes.RESOURCE_EDITION: edition,
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def build_resource() -> Resource:
|
|
267
|
+
"""Public ``Resource`` builder for the current edition.
|
|
268
|
+
|
|
269
|
+
Used by the on-demand telemetry test-export (#2110) so its canary span carries
|
|
270
|
+
the same service identity (``service.name`` / ``service.version`` /
|
|
271
|
+
``trueppm.edition``) as the real export pipeline — the operator sees the canary
|
|
272
|
+
attributed to this deployment, not an anonymous span.
|
|
273
|
+
"""
|
|
274
|
+
return _build_resource(str(getattr(settings, "TRUEPPM_EDITION", "community")))
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def build_span_exporter(*, timeout: float | None = None) -> Any:
|
|
278
|
+
"""Build a one-off OTLP span exporter from the configured OTLP settings.
|
|
279
|
+
|
|
280
|
+
Shared by the batched tracer provider (the long-lived export pipeline) and the
|
|
281
|
+
on-demand telemetry **test-export** action (#2110), so both resolve endpoint,
|
|
282
|
+
protocol and headers through the exact same path — a canary probe can never
|
|
283
|
+
disagree with the real exporter about where spans go, and there is one place
|
|
284
|
+
the bearer-token headers are read. ``timeout`` (seconds) bounds a single export
|
|
285
|
+
attempt; the test action passes a short bound so a dead collector cannot hang
|
|
286
|
+
the request, while the batch pipeline leaves it unset (the exporter default).
|
|
287
|
+
|
|
288
|
+
The caller owns the returned exporter's lifecycle and must ``shutdown()`` it.
|
|
289
|
+
"""
|
|
290
|
+
endpoint = settings.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
291
|
+
headers = _parse_headers(settings.OTEL_EXPORTER_OTLP_HEADERS)
|
|
292
|
+
kwargs: dict[str, Any] = {"endpoint": endpoint, "headers": headers}
|
|
293
|
+
if timeout is not None:
|
|
294
|
+
kwargs["timeout"] = int(timeout)
|
|
295
|
+
if _is_http_protocol():
|
|
296
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
297
|
+
OTLPSpanExporter as HTTPSpanExporter,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
kwargs["endpoint"] = _http_signal_endpoint(endpoint, HTTP_TRACES_PATH)
|
|
301
|
+
return HTTPSpanExporter(**kwargs)
|
|
302
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
303
|
+
OTLPSpanExporter as GRPCSpanExporter,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
return GRPCSpanExporter(**kwargs)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def build_metric_exporter() -> Any:
|
|
310
|
+
"""Build an OTLP metric exporter from the configured OTLP settings.
|
|
311
|
+
|
|
312
|
+
The metrics counterpart of :func:`build_span_exporter`, kept as its own
|
|
313
|
+
function so both signals resolve endpoint, protocol, headers and — for
|
|
314
|
+
``http/protobuf`` — the per-signal path through one symmetric path that a test
|
|
315
|
+
can construct directly. The ``PeriodicExportingMetricReader`` owns the
|
|
316
|
+
returned exporter's lifecycle.
|
|
317
|
+
"""
|
|
318
|
+
endpoint = settings.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
319
|
+
headers = _parse_headers(settings.OTEL_EXPORTER_OTLP_HEADERS)
|
|
320
|
+
if _is_http_protocol():
|
|
321
|
+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import (
|
|
322
|
+
OTLPMetricExporter as HTTPMetricExporter,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
return HTTPMetricExporter(
|
|
326
|
+
endpoint=_http_signal_endpoint(endpoint, HTTP_METRICS_PATH), headers=headers
|
|
327
|
+
)
|
|
328
|
+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
|
|
329
|
+
OTLPMetricExporter as GRPCMetricExporter,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return GRPCMetricExporter(endpoint=endpoint, headers=headers)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _parse_headers(raw: str) -> dict[str, str] | None:
|
|
336
|
+
"""Parse ``key=value,key2=value2`` OTLP header config into a dict."""
|
|
337
|
+
raw = (raw or "").strip()
|
|
338
|
+
if not raw:
|
|
339
|
+
return None
|
|
340
|
+
headers: dict[str, str] = {}
|
|
341
|
+
for pair in raw.split(","):
|
|
342
|
+
if "=" not in pair:
|
|
343
|
+
continue
|
|
344
|
+
key, _, value = pair.partition("=")
|
|
345
|
+
key = key.strip()
|
|
346
|
+
if key:
|
|
347
|
+
headers[key] = value.strip()
|
|
348
|
+
return headers or None
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _is_http_protocol() -> bool:
|
|
352
|
+
"""True for the HTTP/protobuf OTLP transport, False for gRPC (the default)."""
|
|
353
|
+
return str(settings.OTEL_EXPORTER_OTLP_PROTOCOL).lower().startswith("http")
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
# The OTLP/HTTP per-signal paths from the OTLP specification. gRPC has no
|
|
357
|
+
# per-signal path (the signal is the RPC method), so these apply to HTTP only.
|
|
358
|
+
HTTP_TRACES_PATH = "v1/traces"
|
|
359
|
+
HTTP_METRICS_PATH = "v1/metrics"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _http_signal_endpoint(endpoint: str, signal_path: str) -> str:
|
|
363
|
+
"""Return ``endpoint`` with the OTLP/HTTP per-signal path appended (#2873).
|
|
364
|
+
|
|
365
|
+
Why this exists: the upstream HTTP exporters append ``/v1/traces`` /
|
|
366
|
+
``/v1/metrics`` **only** on the branch that reads the endpoint out of the
|
|
367
|
+
environment — ``self._endpoint = endpoint or environ.get(...)``. Passing
|
|
368
|
+
``endpoint=`` explicitly, as this module does so the value flows from Django
|
|
369
|
+
settings, short-circuits that branch, so the exporter POSTs to the collector
|
|
370
|
+
root. A collector answers the root with 404, and 404 is not in the exporter's
|
|
371
|
+
retry set, so every export fails permanently and silently — the deployment
|
|
372
|
+
emits no telemetry at all.
|
|
373
|
+
|
|
374
|
+
The configured endpoint is treated as a **base** URL, and a trailing OTLP
|
|
375
|
+
signal path is normalized away before the one for this signal is appended. So
|
|
376
|
+
an operator who pastes the full traces URL (which the OTLP spec allows, and
|
|
377
|
+
which upstream itself would double-append) gets it back unchanged for traces
|
|
378
|
+
*and* still gets a working ``/v1/metrics`` for metrics — rather than
|
|
379
|
+
``/v1/traces/v1/traces`` and ``/v1/traces/v1/metrics``, both of which 404.
|
|
380
|
+
Any path prefix in front of the signal path (``https://host/otlp``) is kept.
|
|
381
|
+
"""
|
|
382
|
+
trimmed = endpoint.strip().rstrip("/")
|
|
383
|
+
for known in (HTTP_TRACES_PATH, HTTP_METRICS_PATH):
|
|
384
|
+
suffix = f"/{known}"
|
|
385
|
+
if trimmed.endswith(suffix):
|
|
386
|
+
trimmed = trimmed[: -len(suffix)]
|
|
387
|
+
break
|
|
388
|
+
return f"{trimmed}/{signal_path}"
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _build_sampler() -> Sampler:
|
|
392
|
+
"""Build a trace ``Sampler`` from ``OTEL_TRACES_SAMPLER`` / ``_ARG``.
|
|
393
|
+
|
|
394
|
+
The ``TracerProvider`` in :func:`_build_tracer_provider` is constructed by
|
|
395
|
+
hand rather than through the SDK's ``opentelemetry.sdk.trace.TracerProvider``
|
|
396
|
+
auto-configuration entrypoint. That auto-config path is the *only* thing that
|
|
397
|
+
reads the standard ``OTEL_TRACES_SAMPLER`` / ``OTEL_TRACES_SAMPLER_ARG`` env
|
|
398
|
+
vars, so building the provider manually silently drops them and pins the
|
|
399
|
+
process to the SDK default (``ParentBased(ALWAYS_ON)``) — full-rate export.
|
|
400
|
+
For an API whose span volume is dominated by high-cardinality psycopg DB
|
|
401
|
+
spans, that leaves an operator no knob to throttle trace cost short of
|
|
402
|
+
turning tracing off entirely. This helper re-implements the standard env-var
|
|
403
|
+
contract so those knobs work again.
|
|
404
|
+
|
|
405
|
+
The default (unset env) is ``parentbased_always_on``, which is exactly the
|
|
406
|
+
prior hard-coded behavior — so existing deployments see no change. The ratio
|
|
407
|
+
argument for the ratio-based samplers is read from ``OTEL_TRACES_SAMPLER_ARG``
|
|
408
|
+
and defaults to ``1.0`` (sample everything) when unset or unparseable.
|
|
409
|
+
"""
|
|
410
|
+
from opentelemetry.sdk.trace.sampling import (
|
|
411
|
+
ALWAYS_OFF,
|
|
412
|
+
ALWAYS_ON,
|
|
413
|
+
ParentBased,
|
|
414
|
+
TraceIdRatioBased,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
name = str(settings.OTEL_TRACES_SAMPLER).strip().lower()
|
|
418
|
+
raw_arg = str(settings.OTEL_TRACES_SAMPLER_ARG).strip()
|
|
419
|
+
try:
|
|
420
|
+
ratio = float(raw_arg) if raw_arg else 1.0
|
|
421
|
+
except ValueError:
|
|
422
|
+
logger.warning("Invalid OTEL_TRACES_SAMPLER_ARG %r; falling back to 1.0", raw_arg)
|
|
423
|
+
ratio = 1.0
|
|
424
|
+
|
|
425
|
+
samplers: dict[str, Sampler] = {
|
|
426
|
+
"always_on": ALWAYS_ON,
|
|
427
|
+
"always_off": ALWAYS_OFF,
|
|
428
|
+
"traceidratio": TraceIdRatioBased(ratio),
|
|
429
|
+
"parentbased_always_on": ParentBased(ALWAYS_ON),
|
|
430
|
+
"parentbased_always_off": ParentBased(ALWAYS_OFF),
|
|
431
|
+
"parentbased_traceidratio": ParentBased(TraceIdRatioBased(ratio)),
|
|
432
|
+
}
|
|
433
|
+
sampler = samplers.get(name)
|
|
434
|
+
if sampler is None:
|
|
435
|
+
logger.warning("Unrecognized OTEL_TRACES_SAMPLER %r; using parentbased_always_on", name)
|
|
436
|
+
sampler = ParentBased(ALWAYS_ON)
|
|
437
|
+
return sampler
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _build_tracer_provider(resource: Resource) -> TracerProvider:
|
|
441
|
+
"""Build a ``TracerProvider`` with a batched OTLP span exporter."""
|
|
442
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
443
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
444
|
+
|
|
445
|
+
provider = TracerProvider(resource=resource, sampler=_build_sampler())
|
|
446
|
+
# BatchSpanProcessor exports on its own background thread and is fire-and-forget:
|
|
447
|
+
# export failures are logged and dropped by the SDK and never reach a request.
|
|
448
|
+
# The recorder wrapper (ADR-0601) sits inside the processor so it observes each
|
|
449
|
+
# export's result on that same thread without changing the fire-and-forget path.
|
|
450
|
+
exporter = _wrap_exporter_for_health(build_span_exporter(), signal="traces")
|
|
451
|
+
provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
452
|
+
return provider
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _build_meter_provider(resource: Resource) -> MeterProvider:
|
|
456
|
+
"""Build a ``MeterProvider`` with a periodic OTLP metric reader."""
|
|
457
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
458
|
+
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
|
459
|
+
|
|
460
|
+
exporter = _wrap_exporter_for_health(build_metric_exporter(), signal="metrics")
|
|
461
|
+
reader = PeriodicExportingMetricReader(exporter)
|
|
462
|
+
return MeterProvider(resource=resource, metric_readers=[reader])
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def _wrap_exporter_for_health(exporter: Any, *, signal: str) -> Any:
|
|
466
|
+
"""Wrap an OTLP exporter in the export-health recorder (ADR-0601, #2109).
|
|
467
|
+
|
|
468
|
+
Returns the exporter unchanged when the feature is switched off, or if the
|
|
469
|
+
recorder can't be constructed — the recorder is a best-effort observability
|
|
470
|
+
aid, so a failure to install it must degrade to plain export, never crash
|
|
471
|
+
bootstrap. ``signal`` is ``"traces"`` or ``"metrics"``.
|
|
472
|
+
"""
|
|
473
|
+
if not getattr(settings, "TRUEPPM_OTEL_EXPORT_HEALTH_ENABLED", True):
|
|
474
|
+
return exporter
|
|
475
|
+
try:
|
|
476
|
+
from .export_health import (
|
|
477
|
+
ExportHealthRecorder,
|
|
478
|
+
RecordingMetricExporter,
|
|
479
|
+
RecordingSpanExporter,
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
recorder = ExportHealthRecorder(signal, settings.OTEL_SERVICE_NAME)
|
|
483
|
+
if signal == "traces":
|
|
484
|
+
return RecordingSpanExporter(exporter, recorder)
|
|
485
|
+
return RecordingMetricExporter(exporter, recorder)
|
|
486
|
+
except Exception:
|
|
487
|
+
logger.exception("export-health: recorder install failed; exporting without it")
|
|
488
|
+
return exporter
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def reset_for_testing() -> None:
|
|
492
|
+
"""Reset module state so a test can re-run :func:`bootstrap` under new settings.
|
|
493
|
+
|
|
494
|
+
Intended for the test suite only — production bootstraps exactly once. Does
|
|
495
|
+
not tear down any globally-installed OTel provider (the OTel API forbids
|
|
496
|
+
replacing a set provider), so tests that need a clean global provider should
|
|
497
|
+
run in a subprocess or assert on the returned context rather than the global.
|
|
498
|
+
|
|
499
|
+
Also reverses any Phase 1 auto-instrumentation (#709) and clears the Phase 2
|
|
500
|
+
metrics-registration guard (#710) so a subsequent ``instrument()`` /
|
|
501
|
+
``install_metrics()`` starts from a clean state. Both are imported lazily to
|
|
502
|
+
avoid the import cycle (they depend on this module).
|
|
503
|
+
"""
|
|
504
|
+
global _context, _bootstrapped
|
|
505
|
+
_hooks.clear()
|
|
506
|
+
_context = None
|
|
507
|
+
_bootstrapped = False
|
|
508
|
+
from . import instrumentation, metrics
|
|
509
|
+
|
|
510
|
+
instrumentation.reset_for_testing()
|
|
511
|
+
metrics.reset_for_testing()
|