diff --git a/src/sentry/api/serializers/models/plugin.py b/src/sentry/api/serializers/models/plugin.py index 19f059a1b54a30..a6c5d0dd84e98e 100644 --- a/src/sentry/api/serializers/models/plugin.py +++ b/src/sentry/api/serializers/models/plugin.py @@ -67,7 +67,6 @@ def serialize(self, obj, attrs, user, **kwargs): "hasConfiguration": obj.has_project_conf(), "metadata": obj.get_metadata(), "contexts": contexts, - "status": obj.get_status(), "doc": doc, "firstPartyAlternative": getattr(obj, "alternative", None), "deprecationDate": ( diff --git a/src/sentry/integrations/jira/client.py b/src/sentry/integrations/jira/client.py index 7514c14b6a2613..69cfede42d09b4 100644 --- a/src/sentry/integrations/jira/client.py +++ b/src/sentry/integrations/jira/client.py @@ -161,11 +161,6 @@ def get_versions(self, project): def get_priorities(self): return self.get_cached(self.PRIORITIES_URL) - def get_users_for_project(self, project): - # Jira Server wants a project key, while cloud is indifferent. - project_key = self.get_project_key_for_id(project) - return self.get_cached(self.USERS_URL, params={"project": project_key}) - def search_users_for_project(self, project, username): # Jira Server wants a project key, while cloud is indifferent. project_key = self.get_project_key_for_id(project) diff --git a/src/sentry/integrations/jira_server/client.py b/src/sentry/integrations/jira_server/client.py index 4e24db7e037da2..5688cb40cafd7e 100644 --- a/src/sentry/integrations/jira_server/client.py +++ b/src/sentry/integrations/jira_server/client.py @@ -159,11 +159,6 @@ def get_priorities(self): """ return self.get_cached(self.PRIORITIES_URL) - def get_users_for_project(self, project): - # Jira Server wants a project key, while cloud is indifferent. - project_key = self.get_project_key_for_id(project) - return self.get_cached(self.USERS_URL, params={"project": project_key}) - def search_users_for_project(self, project, username): # Jira Server wants a project key, while cloud is indifferent. project_key = self.get_project_key_for_id(project) diff --git a/src/sentry/plugins/base/manager.py b/src/sentry/plugins/base/manager.py index 6edeb483a045dc..143a6037e8f532 100644 --- a/src/sentry/plugins/base/manager.py +++ b/src/sentry/plugins/base/manager.py @@ -61,12 +61,6 @@ def for_project(self, project, version=1): continue yield plugin - def for_site(self, version=1): - for plugin in self.all(version=version): - if not plugin.has_site_conf(): - continue - yield plugin - def get(self, slug): for plugin in self.all(version=None): if plugin.slug == slug: diff --git a/src/sentry/plugins/base/v1.py b/src/sentry/plugins/base/v1.py index 86f0167c17d27e..2ecb2cecfe7d2b 100644 --- a/src/sentry/plugins/base/v1.py +++ b/src/sentry/plugins/base/v1.py @@ -14,7 +14,6 @@ from sentry.plugins.base.response import DeferredResponse from sentry.plugins.base.view import PluggableViewMixin from sentry.plugins.config import PluginConfigMixin -from sentry.plugins.status import PluginStatusMixin from sentry.projects.services.project import RpcProject if TYPE_CHECKING: @@ -37,7 +36,7 @@ def __new__(cls, name, bases, attrs): return new_cls -class IPlugin(local, PluggableViewMixin, PluginConfigMixin, PluginStatusMixin): +class IPlugin(local, PluggableViewMixin, PluginConfigMixin): """ Plugin interface. Should not be inherited from directly. @@ -70,10 +69,6 @@ class IPlugin(local, PluggableViewMixin, PluginConfigMixin, PluginStatusMixin): conf_title: str | _StrPromise | None = None project_conf_form: Any = None - project_conf_template = "sentry/plugins/project_configuration.html" - - site_conf_form: Any = None - site_conf_template = "sentry/plugins/site_configuration.html" # Global enabled state enabled = True @@ -184,44 +179,15 @@ def get_conf_key(self): return self.get_conf_title().lower().replace(" ", "_") return self.conf_key - def get_conf_form(self, project=None): - """ - Returns the Form required to configure the plugin. - - >>> plugin.get_conf_form(project) - """ - if project is not None: - return self.project_conf_form - return self.site_conf_form - - def get_conf_template(self, project=None): - """ - Returns the template required to render the configuration page. - - >>> plugin.get_conf_template(project) - """ - if project is not None: - return self.project_conf_template - return self.site_conf_template - def get_conf_title(self): """ Returns a string representing the title to be shown on the configuration page. """ return self.conf_title or self.get_title() - def has_site_conf(self): - return self.site_conf_form is not None - def has_project_conf(self): return self.project_conf_form is not None - def has_plugin_conf(self): - """ - Checks if the plugin should be returned in the ProjectPluginsEndpoint - """ - return self.has_project_conf() - def can_enable_for_projects(self): """ Returns a boolean describing whether this plugin can be enabled for @@ -249,9 +215,6 @@ def can_configure_for_project(self, project): return True - def get_form_initial(self, project=None): - return {} - # The following methods are specific to web requests def get_title(self) -> str | _StrPromise: @@ -273,19 +236,6 @@ def get_description(self) -> str | None: """ return self.description - def get_resource_links(self) -> Sequence[tuple[str, str]]: - """ - Returns a list of tuples pointing to various resources for this plugin. - - >>> def get_resource_links(self): - >>> return [ - >>> ('Documentation', 'https://docs.sentry.io'), - >>> ('Report Issue', 'https://github.com/getsentry/sentry/issues'), - >>> ('View Source', 'https://github.com/getsentry/sentry'), - >>> ] - """ - return self.resource_links - def get_view_response(self, request, group): self.selected = request.path == self.get_url(group) @@ -329,25 +279,6 @@ def view(self, request, group, **kwargs): >>> return self.render('myplugin/about.html') """ - def before_events(self, request, group_list, **kwargs): - """ - Allows preprocessing of groups in the list view. - - This is generally useful if you need to cache lookups - for something like ``tags`` which would otherwise do - multiple queries. - - If you use this **at all** you should ensure it's already - reset on each execution. - - As an example, here's how we might get a reference to ticket ids we were - storing per event, in an efficient O(1) manner. - - >>> def before_events(self, request, event_list, **kwargs): - >>> prefix = self.get_conf_key() - >>> GroupMeta.objects.get_value_bulk(event_list, '%s:tid' % prefix) - """ - def tags(self, request, group, tag_list, **kwargs): """ Modifies the tag list for a grouped message. @@ -379,22 +310,6 @@ def actions(self, request, group, action_list, **kwargs): """ return action_list - def panels(self, request, group, panel_list, **kwargs): - """ - Modifies the panel list for a grouped message. - - A panel is a tuple containing two elements: - - ('Panel Label', '/uri/to/panel/') - - This must return ``panel_list``. - - >>> def panels(self, request, group, action_list, **kwargs): - >>> panel_list.append((self.get_title(), self.get_url(group))) - >>> return panel_list - """ - return panel_list - def widget(self, request, group, **kwargs): """ Renders as a widget in the group details sidebar. @@ -405,14 +320,6 @@ def widget(self, request, group, **kwargs): # Server side signals which do not have request context - def has_perm(self, user, perm, *objects, **kwargs): - # DEPRECATED: No longer used. - pass - - def missing_perm_response(self, request, perm, *args, **objects): - # DEPRECATED: No longer used. - pass - def is_regression(self, group, event, **kwargs): """ Called on new events when the group's status is resolved. @@ -452,17 +359,6 @@ def get_tags(self, event, **kwargs): >>> return [('tag-name', 'tag-value')] """ - def get_notification_forms(self, **kwargs): - """ - Provides additional UserOption forms for the Notification Settings page. - - Must return an iterable. - - >>> def get_notification_forms(self, **kwargs): - >>> return [MySettingsForm] - """ - return [] - def is_testable(self, **kwargs): """ Returns True if this plugin is able to be tested. diff --git a/src/sentry/plugins/base/v2.py b/src/sentry/plugins/base/v2.py index 75909115896414..f7bbda485acdf7 100644 --- a/src/sentry/plugins/base/v2.py +++ b/src/sentry/plugins/base/v2.py @@ -11,7 +11,6 @@ from sentry.plugins.base.response import DeferredResponse from sentry.plugins.config import PluginConfigMixin from sentry.plugins.interfaces.releasehook import ReleaseHook -from sentry.plugins.status import PluginStatusMixin if TYPE_CHECKING: from django.utils.functional import _StrPromise @@ -35,7 +34,7 @@ def __new__(cls, name, bases, attrs): return new_cls -class IPlugin2(local, PluginConfigMixin, PluginStatusMixin): +class IPlugin2(local, PluginConfigMixin): """ Plugin interface. Should not be inherited from directly. @@ -68,7 +67,6 @@ class IPlugin2(local, PluginConfigMixin, PluginStatusMixin): conf_title: str | _StrPromise | None = None project_conf_form: Any = None - project_conf_template = "sentry/plugins/project_configuration.html" # Global enabled state enabled = True @@ -175,44 +173,15 @@ def get_conf_key(self): self.conf_key = self.get_conf_title().lower().replace(" ", "_") return self.conf_key - def get_conf_form(self, project=None): - """ - Returns the Form required to configure the plugin. - - >>> plugin.get_conf_form(project) - """ - if project is not None: - return self.project_conf_form - return self.site_conf_form - - def get_conf_template(self, project=None): - """ - Returns the template required to render the configuration page. - - >>> plugin.get_conf_template(project) - """ - if project is not None: - return self.project_conf_template - return self.site_conf_template - def get_conf_title(self): """ Returns a string representing the title to be shown on the configuration page. """ return self.conf_title or self.get_title() - def get_form_initial(self, project=None): - return {} - def has_project_conf(self): return self.project_conf_form is not None - def has_plugin_conf(self): - """ - Checks if the plugin should be returned in the ProjectPluginsEndpoint - """ - return self.has_project_conf() - def can_configure_for_project(self, project): """ Checks if the plugin can be configured for a specific project. @@ -273,19 +242,6 @@ def get_description(self): """ return self.description - def get_resource_links(self): - """ - Returns a list of tuples pointing to various resources for this plugin. - - >>> def get_resource_links(self): - >>> return [ - >>> ('Documentation', 'https://docs.sentry.io'), - >>> ('Report Issue', 'https://github.com/getsentry/sentry/issues'), - >>> ('View Source', 'https://github.com/getsentry/sentry'), - >>> ] - """ - return self.resource_links - def get_rules(self, **kwargs): """ Return a list of Rule classes to add to the registry. @@ -373,23 +329,6 @@ def get_stacktrace_processors(self, data, stacktrace_infos, return [CocoaProcessor(data, stacktrace_infos)] """ - def get_feature_hooks(self, **kwargs): - """ - Return a list of callables to check for feature status. - - >>> from sentry.features import FeatureHandler - >>> - >>> class NoRegistration(FeatureHandler): - >>> features = set(['auth:register']) - >>> - >>> def has(self, feature, actor): - >>> return False - - >>> def get_feature_hooks(self, **kwargs): - >>> return [NoRegistration()] - """ - return [] - def get_release_hook(self) -> type[ReleaseHook] | None: """ Return an implementation of ``ReleaseHook``. diff --git a/src/sentry/plugins/bases/issue.py b/src/sentry/plugins/bases/issue.py index 3c2d0c832676a1..4280692924b917 100644 --- a/src/sentry/plugins/bases/issue.py +++ b/src/sentry/plugins/bases/issue.py @@ -91,12 +91,6 @@ def get_new_issue_title(self, **kwargs): """ return "Create %s Issue" % self.get_title() - def get_unlink_issue_title(self, **kwargs): - """ - Return a string for the "Unlink plugin issue" action label. - """ - return "Unlink %s Issue" % self.get_title() - def get_new_issue_form(self, request: Request, group, event, **kwargs): """ Return a Form for the "Create new issue" page. @@ -119,12 +113,6 @@ def get_issue_url(self, group, issue_id: str) -> str: """ raise NotImplementedError - def get_issue_title_by_id(self, request: Request, group, issue_id): - """ - Given an issue_id return the issue's title. - """ - raise NotImplementedError - def get_issue_label(self, group, issue_id) -> str: """ Given an issue_id (string) return a string representing the issue. @@ -157,10 +145,6 @@ def has_auth_configured(self, **kwargs): return self.auth_provider in get_auth_providers() - def handle_unlink_issue(self, request: Request, group, **kwargs): - GroupMeta.objects.unset_value(group, "%s:tid" % self.get_conf_key()) - return self.redirect(group.get_absolute_url()) - def view(self, request: Request, group, **kwargs): has_auth_configured = self.has_auth_configured() if not (has_auth_configured and self.is_configured(project=group.project)): @@ -269,8 +253,5 @@ def tags(self, request: Request, group, tag_list, **kwargs): return tag_list - def get_issue_doc_html(self, **kwargs): - return "" - IssuePlugin = IssueTrackingPlugin diff --git a/src/sentry/plugins/bases/notify.py b/src/sentry/plugins/bases/notify.py index 7016bb830a93e0..c970ac2031df7b 100644 --- a/src/sentry/plugins/bases/notify.py +++ b/src/sentry/plugins/bases/notify.py @@ -1,6 +1,5 @@ import logging from urllib.error import HTTPError as UrllibHTTPError -from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from django import forms from requests.exceptions import HTTPError, SSLError @@ -20,29 +19,12 @@ class NotificationConfigurationForm(forms.Form): pass -class BaseNotificationUserOptionsForm(forms.Form): - def __init__(self, plugin, user, *args, **kwargs): - self.plugin = plugin - self.user = user - super().__init__(*args, **kwargs) - - def get_title(self): - return self.plugin.get_conf_title() - - def get_description(self): - return "" - - def save(self): - raise NotImplementedError - - class NotificationPlugin(Plugin): slug = "" description = ( "Notify project members when a new event is seen for the first time, or when an " "already resolved event has changed back to unresolved." ) - # site_conf_form = NotificationConfigurationForm project_conf_form: type[forms.Form] = NotificationConfigurationForm def get_plugin_type(self): @@ -203,23 +185,3 @@ def test_configuration_and_get_test_results(self, project): else: test_results = "No errors returned" return test_results - - def get_notification_doc_html(self, **kwargs): - return "" - - def add_notification_referrer_param(self, url): - if self.slug: - parsed_url = urlparse(url) - query = parse_qs(parsed_url.query) - query["referrer"] = self.slug - - url_list = list(parsed_url) - url_list[4] = urlencode(query, doseq=True) - return urlunparse(url_list) - - return url - - -# Backwards-compatibility -NotifyConfigurationForm = NotificationConfigurationForm -NotifyPlugin = NotificationPlugin diff --git a/src/sentry/plugins/config.py b/src/sentry/plugins/config.py index 2b53fd594815e2..66b3a4c7e111ec 100644 --- a/src/sentry/plugins/config.py +++ b/src/sentry/plugins/config.py @@ -10,8 +10,6 @@ from .providers import ProviderMixin from .validators import DEFAULT_VALIDATORS -VALIDATOR_ERRORS = (forms.ValidationError, serializers.ValidationError, PluginError) - ERR_FIELD_REQUIRED = "This field is required." diff --git a/src/sentry/plugins/interfaces/releasehook.py b/src/sentry/plugins/interfaces/releasehook.py index af1d5f5d300356..37b8f36bfcbd16 100644 --- a/src/sentry/plugins/interfaces/releasehook.py +++ b/src/sentry/plugins/interfaces/releasehook.py @@ -15,23 +15,6 @@ class ReleaseHook: def __init__(self, project): self.project = project - def start_release(self, version, **values): - if not Release.is_valid_version(version): - raise HookValidationError("Invalid release version: %s" % version) - - try: - with transaction.atomic(router.db_for_write(Release)): - release = Release.objects.create( - version=version, organization_id=self.project.organization_id, **values - ) - except IntegrityError: - release = Release.objects.get( - version=version, organization_id=self.project.organization_id - ) - release.update(**values) - - release.add_project(self.project) - # TODO(dcramer): this is being used by the release details endpoint, but # it'd be ideal if most if not all of this logic lived there, and this # hook simply called out to the endpoint diff --git a/src/sentry/plugins/providers/base.py b/src/sentry/plugins/providers/base.py index 0e78bcf0459bae..78aa5960d60afd 100644 --- a/src/sentry/plugins/providers/base.py +++ b/src/sentry/plugins/providers/base.py @@ -32,48 +32,6 @@ def link_auth(self, user, organization, data): rpc_organization = serialize_rpc_organization(org=organization) usersocialauth_service.link_auth(usa=usa, organization=rpc_organization) - def get_available_auths(self, user, organization, integrations, social_auths, **kwargs): - if self.auth_provider is None: - return [] - - social_auths_by_id = {usa.id: usa for usa in social_auths} - linked_social_auths = set() - - auths = [] - for i in integrations: - associated_auth = i.default_auth_id and social_auths_by_id[i.default_auth_id] - if associated_auth: - linked_social_auths.add(associated_auth.id) - auths.append( - { - "defaultAuthId": i.default_auth_id, - "user": associated_auth and {"email": associated_auth.user.email}, - "externalId": i.external_id, - "integrationId": str(i.id), - "linked": True, - } - ) - auths.extend( - [ - { - "defaultAuthId": sa.id, - "user": {"email": sa.user.email}, - "externalId": sa.uid, - "integrationId": None, - "linked": False, - } - for sa in social_auths - if sa.id not in linked_social_auths - ] - ) - return auths - - def get_auth_url(self, user, **kwargs): - if self.auth_provider is None: - return - - return reverse("socialauth_associate", args=[self.auth_provider]) - def get_auth(self, user: RpcUser | User, **kwargs) -> RpcUserSocialAuth | None: if self.auth_provider is None: return None diff --git a/src/sentry/plugins/status.py b/src/sentry/plugins/status.py deleted file mode 100644 index c587eead89a76f..00000000000000 --- a/src/sentry/plugins/status.py +++ /dev/null @@ -1,15 +0,0 @@ -__all__ = ["PluginStatusMixin"] - - -class PluginStatus: - BETA = "beta" - STABLE = "stable" - UNKNOWN = "unknown" - - -class PluginStatusMixin: - status = PluginStatus.UNKNOWN - - @classmethod - def get_status(cls): - return cls.status diff --git a/src/sentry_plugins/github/plugin.py b/src/sentry_plugins/github/plugin.py index 84df8a3c8b6a8c..0115beab25e7a5 100644 --- a/src/sentry_plugins/github/plugin.py +++ b/src/sentry_plugins/github/plugin.py @@ -8,7 +8,6 @@ from sentry import options from sentry.exceptions import PluginError from sentry.integrations.base import FeatureDescription, IntegrationFeatures -from sentry.integrations.models.integration import Integration from sentry.integrations.services.integration.model import RpcIntegration from sentry.integrations.services.integration.service import integration_service from sentry.locks import locks @@ -429,33 +428,6 @@ class GitHubAppsRepositoryProvider(GitHubRepositoryProvider): auth_provider = "github_apps" logger = logging.getLogger("sentry.plugins.github_apps") - def get_install_url(self): - return options.get("github.apps-install-url") - - def get_available_auths(self, user, organization, integrations, social_auths, **kwargs): - allowed_gh_installations = set(self.get_installations(user)) - - linked_integrations = {i.id for i in integrations} - - _integrations = list(Integration.objects.filter(external_id__in=allowed_gh_installations)) - - # add in integrations that might have been set up for org - # by users w diff permissions - _integrations.extend( - [i for i in integrations if i.external_id not in allowed_gh_installations] - ) - - return [ - { - "defaultAuthId": None, - "user": None, - "externalId": i.external_id, - "integrationId": str(i.id), - "linked": i.id in linked_integrations, - } - for i in _integrations - ] - def link_auth(self, user, organization, data): integration_id = data["integration_id"] diff --git a/src/sentry_plugins/jira/client.py b/src/sentry_plugins/jira/client.py index 11ee44ef77c8f0..a89d18254c8455 100644 --- a/src/sentry_plugins/jira/client.py +++ b/src/sentry_plugins/jira/client.py @@ -28,7 +28,6 @@ class JiraClient(ApiClient): ISSUE_URL = "/rest/api/2/issue/{}" SEARCH_URL = "/rest/api/2/search/" COMMENT_URL = "/rest/api/2/issue/{}/comment" - HTTP_TIMEOUT = 5 plugin_name = "jira" cache_time = 60 @@ -75,9 +74,6 @@ def get_versions(self, project): def get_priorities(self): return self.get_cached(self.PRIORITIES_URL) - def get_users_for_project(self, project): - return self.get(self.USERS_URL, params={"project": project}) - def search_users_for_project(self, project, username): return self.get(self.USERS_URL, params={"project": project, "username": username}) diff --git a/src/sentry_plugins/opsgenie/plugin.py b/src/sentry_plugins/opsgenie/plugin.py index 7f0e1fe8473098..bf35dcdbc65f82 100644 --- a/src/sentry_plugins/opsgenie/plugin.py +++ b/src/sentry_plugins/opsgenie/plugin.py @@ -73,9 +73,6 @@ class OpsGeniePlugin(CorePluginMixin, notify.NotificationPlugin): def is_configured(self, project) -> bool: return all(self.get_option(k, project) for k in ("api_key", "alert_url")) - def get_form_initial(self, project=None): - return {"alert_url": "https://api.opsgenie.com/v2/alerts"} - @staticmethod def build_payload(group, event, triggering_rules): return { diff --git a/src/sentry_plugins/pagerduty/plugin.py b/src/sentry_plugins/pagerduty/plugin.py index e1def62ef41639..09976b7ed3e305 100644 --- a/src/sentry_plugins/pagerduty/plugin.py +++ b/src/sentry_plugins/pagerduty/plugin.py @@ -1,5 +1,5 @@ from sentry.integrations.base import FeatureDescription, IntegrationFeatures -from sentry.plugins.bases.notify import NotifyPlugin +from sentry.plugins.bases.notify import NotificationPlugin from sentry.utils.http import absolute_uri from sentry_plugins.base import CorePluginMixin from sentry_plugins.utils import get_secret_field_config @@ -7,7 +7,7 @@ from .client import PagerDutyPluginClient -class PagerDutyPlugin(CorePluginMixin, NotifyPlugin): +class PagerDutyPlugin(CorePluginMixin, NotificationPlugin): description = "Send alerts to PagerDuty." slug = "pagerduty" title = "PagerDuty" diff --git a/src/sentry_plugins/pivotal/plugin.py b/src/sentry_plugins/pivotal/plugin.py index f1ec6b1a344afb..83f7fc3e03c1b8 100644 --- a/src/sentry_plugins/pivotal/plugin.py +++ b/src/sentry_plugins/pivotal/plugin.py @@ -179,14 +179,6 @@ def get_issue_label(self, group, issue_id: str) -> str: def get_issue_url(self, group, issue_id: str) -> str: return "https://www.pivotaltracker.com/story/show/%s" % issue_id - def get_issue_title_by_id(self, request: Request, group, issue_id): - _url = "{}/{}".format(self.build_api_url(group, "stories"), issue_id) - req = self.make_api_request(group.project, _url) - - body = safe_urlread(req) - json_resp = json.loads(body) - return json_resp["name"] - def get_configure_plugin_fields(self, project, **kwargs): token = self.get_option("token", project) helptext = ( diff --git a/src/sentry_plugins/pushover/plugin.py b/src/sentry_plugins/pushover/plugin.py index 1d05d304c01057..b704e613d2deb4 100644 --- a/src/sentry_plugins/pushover/plugin.py +++ b/src/sentry_plugins/pushover/plugin.py @@ -1,7 +1,7 @@ from sentry.exceptions import PluginError from sentry.integrations.base import FeatureDescription, IntegrationFeatures from sentry.plugins.base.structs import Notification -from sentry.plugins.bases.notify import NotifyPlugin +from sentry.plugins.bases.notify import NotificationPlugin from sentry_plugins.base import CorePluginMixin from sentry_plugins.utils import get_secret_field_config @@ -14,7 +14,7 @@ """ -class PushoverPlugin(CorePluginMixin, NotifyPlugin): +class PushoverPlugin(CorePluginMixin, NotificationPlugin): description = DESCRIPTION slug = "pushover" title = "Pushover" diff --git a/src/sentry_plugins/redmine/forms.py b/src/sentry_plugins/redmine/forms.py index 5fb0dbcc8710b1..438355a22dd0f0 100644 --- a/src/sentry_plugins/redmine/forms.py +++ b/src/sentry_plugins/redmine/forms.py @@ -1,112 +1,6 @@ from __future__ import annotations -from typing import Any - from django import forms -from django.utils.translation import gettext_lazy as _ - -from sentry.utils import json -from sentry.utils.forms import set_field_choices - -from .client import RedmineClient - - -class RedmineOptionsForm(forms.Form): - host = forms.URLField(help_text=_("e.g. http://bugs.redmine.org"), assume_scheme="https") - key = forms.CharField( - widget=forms.TextInput(attrs={"class": "span9"}), - help_text="Your API key is available on your account page after enabling the Rest API (Administration -> Settings -> Authentication)", - ) - project_id = forms.TypedChoiceField(label="Project", coerce=int) - tracker_id = forms.TypedChoiceField(label="Tracker", coerce=int) - default_priority = forms.TypedChoiceField(label="Default Priority", coerce=int) - extra_fields = forms.CharField( - widget=forms.Textarea(attrs={"rows": 5, "class": "span9"}), - help_text="Extra attributes (custom fields, status id, etc.) in JSON format", - label="Extra Fields", - required=False, - ) - - def __init__(self, data=None, **kwargs): - super().__init__(data=data, **kwargs) - - initial = kwargs.get("initial") or {} - for key, value in self.data.items(): - initial[key.lstrip(self.prefix or "")] = value - - has_credentials = all(initial.get(k) for k in ("host", "key")) - client = None - if has_credentials: - client = RedmineClient(initial["host"], initial["key"]) - try: - projects = client.get_projects() - except Exception: - has_credentials = False - else: - project_choices = [ - (p["id"], "{} ({})".format(p["name"], p["identifier"])) - for p in projects["projects"] - ] - set_field_choices(self.fields["project_id"], project_choices) - - if client is not None and has_credentials: - try: - trackers = client.get_trackers() - except Exception: - del self.fields["tracker_id"] - else: - tracker_choices = [(p["id"], p["name"]) for p in trackers["trackers"]] - set_field_choices(self.fields["tracker_id"], tracker_choices) - - try: - priorities = client.get_priorities() - except Exception: - del self.fields["default_priority"] - else: - tracker_choices = [(p["id"], p["name"]) for p in priorities["issue_priorities"]] - set_field_choices(self.fields["default_priority"], tracker_choices) - - if not has_credentials: - del self.fields["project_id"] - del self.fields["tracker_id"] - del self.fields["default_priority"] - - def clean(self) -> dict[str, Any] | None: - cd = self.cleaned_data - if cd.get("host") and cd.get("key"): - client = RedmineClient(cd["host"], cd["key"]) - try: - client.get_projects() - except Exception: - raise forms.ValidationError("There was an issue authenticating with Redmine") - return cd - - def clean_host(self): - """ - Strip forward slashes off any url passed through the form. - """ - url = self.cleaned_data.get("host") - if url: - return url.rstrip("/") - return url - - def clean_extra_fields(self): - """ - Ensure that the value provided is either a valid JSON dictionary, - or the empty string. - """ - extra_fields_json = self.cleaned_data["extra_fields"].strip() - if not extra_fields_json: - return "" - - try: - extra_fields_dict = json.loads(extra_fields_json) - except ValueError: - raise forms.ValidationError("Invalid JSON specified") - - if not isinstance(extra_fields_dict, dict): - raise forms.ValidationError("JSON dictionary must be specified") - return json.dumps(extra_fields_dict) class RedmineNewIssueForm(forms.Form): diff --git a/src/sentry_plugins/segment/plugin.py b/src/sentry_plugins/segment/plugin.py index 050ad82a6a322b..08ae7d27c949ee 100644 --- a/src/sentry_plugins/segment/plugin.py +++ b/src/sentry_plugins/segment/plugin.py @@ -43,32 +43,6 @@ def get_config(self, project, user=None, initial=None, add_additional_fields: bo def get_rate_limit(self): return (200, 1) - def get_event_props(self, event): - props = { - "eventId": event.event_id, - "transaction": event.get_tag("transaction") or "", - "release": event.get_tag("sentry:release") or "", - "level": event.get_tag("level") or "", - "environment": event.get_tag("environment") or "", - } - if "request" in event.interfaces: - http = event.interfaces["request"] - headers = http.headers - if not isinstance(headers, dict): - headers = dict(headers or ()) - - props.update( - { - "requestUrl": http.url, - "requestMethod": http.method, - "requestReferer": headers.get("Referer", ""), - } - ) - if "exception" in event.interfaces: - exc = event.interfaces["exception"].values[0] - props.update({"exceptionType": exc.type}) - return props - # https://segment.com/docs/spec/track/ def get_event_payload(self, event): context = {"library": {"name": "sentry", "version": self.version}} diff --git a/src/sentry_plugins/sessionstack/plugin.py b/src/sentry_plugins/sessionstack/plugin.py index 54603def4efc8b..f0a95ee0659f88 100644 --- a/src/sentry_plugins/sessionstack/plugin.py +++ b/src/sentry_plugins/sessionstack/plugin.py @@ -33,10 +33,6 @@ class SessionStackPlugin(CorePluginMixin, Plugin2): conf_key = slug required_field = "account_email" - sessionstack_resource_links = [ - ("Documentation", "http://docs.sessionstack.com/integrations/sentry/") - ] - feature_descriptions = [ FeatureDescription( """ @@ -46,9 +42,6 @@ class SessionStackPlugin(CorePluginMixin, Plugin2): ) ] - def get_resource_links(self): - return self.resource_links + self.sessionstack_resource_links - def has_project_conf(self): return True diff --git a/src/sentry_plugins/victorops/plugin.py b/src/sentry_plugins/victorops/plugin.py index d3ec87e9cd9350..e9b466af5e4ff4 100644 --- a/src/sentry_plugins/victorops/plugin.py +++ b/src/sentry_plugins/victorops/plugin.py @@ -1,5 +1,5 @@ from sentry.integrations.base import FeatureDescription, IntegrationFeatures -from sentry.plugins.bases.notify import NotifyPlugin +from sentry.plugins.bases.notify import NotificationPlugin from sentry.shared_integrations.exceptions import ApiError from sentry_plugins.base import CorePluginMixin from sentry_plugins.utils import get_secret_field_config @@ -21,7 +21,7 @@ """ -class VictorOpsPlugin(CorePluginMixin, NotifyPlugin): +class VictorOpsPlugin(CorePluginMixin, NotificationPlugin): description = DESCRIPTION slug = "victorops" title = "VictorOps" diff --git a/tests/sentry/api/endpoints/test_project_plugins.py b/tests/sentry/api/endpoints/test_project_plugins.py index 42084c28f382d3..8ca3402c49fe92 100644 --- a/tests/sentry/api/endpoints/test_project_plugins.py +++ b/tests/sentry/api/endpoints/test_project_plugins.py @@ -44,6 +44,5 @@ def assert_plugin_shape(self, plugin): assert "shortName" in plugin assert "slug" in plugin assert "type" in plugin - assert "status" in plugin assert "features" in plugin assert "featureDescriptions" in plugin diff --git a/tests/sentry/plugins/bases/test_notify.py b/tests/sentry/plugins/bases/test_notify.py index 03eefc952a4e97..2282d6fe65698e 100644 --- a/tests/sentry/plugins/bases/test_notify.py +++ b/tests/sentry/plugins/bases/test_notify.py @@ -1,5 +1,4 @@ from unittest import mock -from urllib.parse import parse_qs, urlparse from requests.exceptions import HTTPError, SSLError @@ -19,28 +18,7 @@ def is_configured(self, project) -> bool: return True -class NotifyPlugin(TestCase): - def test_add_notification_referrer_param(self): - n = DummyNotificationPlugin() - n.slug = "slack" - url = "https://sentry.io/" - assert n.add_notification_referrer_param(url) == url + "?referrer=" + n.slug - - url = "https://sentry.io/?referrer=notslack" - assert n.add_notification_referrer_param(url) == "https://sentry.io/?referrer=slack" - - url = "https://sentry.io/?utm_source=google" - with_referrer = n.add_notification_referrer_param(url) - - # XXX(py3): Handle ordering differences between py2/3 - assert parse_qs(urlparse(with_referrer).query) == parse_qs( - "referrer=slack&utm_source=google" - ) - - n.slug = "" - url = "https://sentry.io/" - assert n.add_notification_referrer_param(url) == "https://sentry.io/" - +class NotifyPluginTest(TestCase): def test_notify_failure(self): errors = ( ApiError("The server is sad"), diff --git a/tests/sentry/plugins/interfaces/test_releasehook.py b/tests/sentry/plugins/interfaces/test_releasehook.py index 4266d60899fbbd..aaf22a99a4661c 100644 --- a/tests/sentry/plugins/interfaces/test_releasehook.py +++ b/tests/sentry/plugins/interfaces/test_releasehook.py @@ -1,8 +1,3 @@ -import pytest - -__all__ = ["ReleaseHook"] - -from sentry.exceptions import HookValidationError from sentry.models.commit import Commit from sentry.models.release import Release from sentry.models.releases.release_project import ReleaseProject @@ -10,67 +5,6 @@ from sentry.testutils.cases import TestCase -class StartReleaseTest(TestCase): - def test_minimal(self): - project = self.create_project() - version = "bbee5b51f84611e4b14834363b8514c2" - - hook = ReleaseHook(project) - hook.start_release(version) - - release = Release.objects.get(organization_id=project.organization_id, version=version) - assert release.organization - assert ReleaseProject.objects.get(release=release, project=project) - - def test_bad_version(self): - project = self.create_project() - hook = ReleaseHook(project) - - version = "" - with pytest.raises(HookValidationError): - hook.start_release(version) - - with pytest.raises(HookValidationError): - hook.finish_release(version) - - with pytest.raises(HookValidationError): - hook.set_commits(version, []) - - version = "." - with pytest.raises(HookValidationError): - hook.start_release(version) - - with pytest.raises(HookValidationError): - hook.finish_release(version) - - with pytest.raises(HookValidationError): - hook.set_commits(version, []) - - version = ".." - with pytest.raises(HookValidationError): - hook.start_release(version) - - with pytest.raises(HookValidationError): - hook.finish_release(version) - - with pytest.raises(HookValidationError): - hook.set_commits(version, []) - - def test_update_release(self): - project = self.create_project() - version = "bbee5b51f84611e4b14834363b8514c2" - r = Release.objects.create(organization_id=project.organization_id, version=version) - r.add_project(project) - - hook = ReleaseHook(project) - hook.start_release(version) - - release = Release.objects.get( - organization_id=project.organization_id, projects=project, version=version - ) - assert release.organization == project.organization - - class FinishReleaseTest(TestCase): def test_minimal(self): project = self.create_project() @@ -84,18 +18,6 @@ def test_minimal(self): assert release.organization assert ReleaseProject.objects.get(release=release, project=project) - def test_update_release(self): - project = self.create_project() - version = "bbee5b51f84611e4b14834363b8514c2" - r = Release.objects.create(organization_id=project.organization_id, version=version) - r.add_project(project) - - hook = ReleaseHook(project) - hook.start_release(version) - - release = Release.objects.get(projects=project, version=version) - assert release.organization == project.organization - class SetCommitsTest(TestCase): def test_minimal(self):