The same logical events (link, unlink, feature state changed, feature deleted) dispatch per-provider from multiple unrelated sites today. Adding a new VCS (Bitbucket, say) means touching all of these files and re-learning the conventions each time.
Current state
After #7306 and #7327, integrations/vcs/services.py hosts:
dispatch_vcs_on_resource_create(resource)
dispatch_vcs_on_resource_destroy(resource)
FeatureExternalResourceViewSet.perform_create and .perform_destroy delegate to these. GitLab side effects (log, webhook register/deregister, initial tag, tag clear, link/unlink comment) all flow through the dispatcher via namespaced calls (from integrations.gitlab import services as gitlab), and the GitLab-specific apply_gitlab_tag / deregister_gitlab_webhook lifecycle hooks on FeatureExternalResource are gone.
Still to do
View-level, outside the dispatcher:
FeatureExternalResourceViewSet.create still owns the GitHub URL preflight regex and inline label_github_issue_pr call.
Serializer-level:
- State change:
FeatureStateSerializerBasic.save calls call_github_task (GitHub) and post_gitlab_state_change_comment_for_feature_state (GitLab) directly. No dispatch_vcs_on_feature_state_changed yet.
features/versioning/serializers.py — same split for the v2 versioning flow.
Model-level hooks still present — consolidate to single VCS hook per model:
FeatureExternalResource.notify_github_on_link (AFTER_SAVE, type is GITHUB_ISSUE/GITHUB_PR) — applies GitHub tag + link comment.
FeatureExternalResource.notify_github_on_unlink (BEFORE_DELETE, type is GITHUB_ISSUE/GITHUB_PR) — unlink comment to GitHub.
Feature.create_github_comment (AFTER_SAVE) — flag-deleted comment to GitHub.
Feature.create_gitlab_comment (AFTER_SAVE) — flag-deleted comment to GitLab.
Proposed shape for the rest
Extend integrations/vcs/services.py with:
dispatch_vcs_on_feature_state_changed(feature_state)
dispatch_vcs_on_feature_deleted(feature_name, feature_id, project_id)
Port each remaining trigger behind these:
- Move the four model-level hooks above into the dispatcher's create/destroy paths (for the FER hooks) and the feature-deleted dispatcher (for the
Feature hooks). Model-level triggers should be a last resort; when a side effect is driven by a viewset action, the dispatcher called from the viewset is the honest place for it.
- Move the two serializer dispatch sites behind
dispatch_vcs_on_feature_state_changed.
- Decide whether the GitHub URL preflight regex stays in the view or moves into a provider-owned validator hook called from
dispatch_vcs_on_resource_create.
The current implementation uses explicit if resource.type in GITLAB_RESOURCE_TYPES: branches rather than a registry protocol (AppConfig.ready()). Simple, fine for two providers; worth revisiting if a third joins.
Not in scope
- Emit-parity between GitHub and GitLab (state-change, delete comments for GitHub). Separate product call.
- Log-event consolidation — falls out of the dispatch model naturally.
The same logical events (link, unlink, feature state changed, feature deleted) dispatch per-provider from multiple unrelated sites today. Adding a new VCS (Bitbucket, say) means touching all of these files and re-learning the conventions each time.
Current state
After #7306 and #7327,
integrations/vcs/services.pyhosts:dispatch_vcs_on_resource_create(resource)dispatch_vcs_on_resource_destroy(resource)FeatureExternalResourceViewSet.perform_createand.perform_destroydelegate to these. GitLab side effects (log, webhook register/deregister, initial tag, tag clear, link/unlink comment) all flow through the dispatcher via namespaced calls (from integrations.gitlab import services as gitlab), and the GitLab-specificapply_gitlab_tag/deregister_gitlab_webhooklifecycle hooks onFeatureExternalResourceare gone.Still to do
View-level, outside the dispatcher:
FeatureExternalResourceViewSet.createstill owns the GitHub URL preflight regex and inlinelabel_github_issue_prcall.Serializer-level:
FeatureStateSerializerBasic.savecallscall_github_task(GitHub) andpost_gitlab_state_change_comment_for_feature_state(GitLab) directly. Nodispatch_vcs_on_feature_state_changedyet.features/versioning/serializers.py— same split for the v2 versioning flow.Model-level hooks still present — consolidate to single VCS hook per model:
FeatureExternalResource.notify_github_on_link(AFTER_SAVE, type isGITHUB_ISSUE/GITHUB_PR) — applies GitHub tag + link comment.FeatureExternalResource.notify_github_on_unlink(BEFORE_DELETE, type isGITHUB_ISSUE/GITHUB_PR) — unlink comment to GitHub.Feature.create_github_comment(AFTER_SAVE) — flag-deleted comment to GitHub.Feature.create_gitlab_comment(AFTER_SAVE) — flag-deleted comment to GitLab.Proposed shape for the rest
Extend
integrations/vcs/services.pywith:dispatch_vcs_on_feature_state_changed(feature_state)dispatch_vcs_on_feature_deleted(feature_name, feature_id, project_id)Port each remaining trigger behind these:
Featurehooks). Model-level triggers should be a last resort; when a side effect is driven by a viewset action, the dispatcher called from the viewset is the honest place for it.dispatch_vcs_on_feature_state_changed.dispatch_vcs_on_resource_create.The current implementation uses explicit
if resource.type in GITLAB_RESOURCE_TYPES:branches rather than a registry protocol (AppConfig.ready()). Simple, fine for two providers; worth revisiting if a third joins.Not in scope