diff --git a/airflow/providers/atlassian/jira/hooks/jira.py b/airflow/providers/atlassian/jira/hooks/jira.py index 3862d86bbd01c..ed706aed958ce 100644 --- a/airflow/providers/atlassian/jira/hooks/jira.py +++ b/airflow/providers/atlassian/jira/hooks/jira.py @@ -18,11 +18,12 @@ """Hook for JIRA.""" from __future__ import annotations +import warnings from typing import Any from atlassian import Jira -from airflow.exceptions import AirflowException +from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning from airflow.hooks.base import BaseHook @@ -56,12 +57,21 @@ def get_conn(self) -> Jira: conn = self.get_connection(self.jira_conn_id) if conn.extra is not None: extra_options = conn.extra_dejson + verify = extra_options.get("verify", verify) # only required attributes are taken for now, # more can be added ex: timeout, cloud, session # verify - if "verify" in extra_options and extra_options["verify"].lower() == "false": - verify = False + if isinstance(verify, str): + warnings.warn( + "Extra parameter `verify` using str is deprecated and will be removed " + "in a future release. Please use `verify` using bool instead.", + AirflowProviderDeprecationWarning, + stacklevel=2, + ) + verify = True + if extra_options["verify"].lower() == "false": + verify = False self.client = Jira( url=conn.host, @@ -72,3 +82,21 @@ def get_conn(self) -> Jira: ) return self.client + + @classmethod + def get_connection_form_widgets(cls) -> dict[str, Any]: + """Returns connection widgets to add to connection form.""" + from flask_babel import lazy_gettext + from wtforms import BooleanField + + return { + "verify": BooleanField(lazy_gettext("Verify SSL"), default=True), + } + + @classmethod + def get_ui_field_behaviour(cls) -> dict[str, Any]: + """Returns custom field behaviour.""" + return { + "hidden_fields": ["schema", "extra"], + "relabeling": {}, + } diff --git a/docs/apache-airflow-providers-atlassian-jira/connections.rst b/docs/apache-airflow-providers-atlassian-jira/connections.rst new file mode 100644 index 0000000000000..e33392f54d8dd --- /dev/null +++ b/docs/apache-airflow-providers-atlassian-jira/connections.rst @@ -0,0 +1,44 @@ + .. Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + .. http://www.apache.org/licenses/LICENSE-2.0 + + .. Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +Jira Connection +=============== + +The Jira connection type enables connection to Atlassian Jira. + +Default Connection IDs +---------------------- + +Jira Hook uses parameter ``jira_conn_id`` for Connection IDs and the value of the +parameter as ``jira_default`` by default. + +Configuring the Connection +-------------------------- +Host + The Jira host (should be with scheme). + +Port + Specify the port to use for connecting to Jira. + +Login + The user that will be used for authentication against the Jira API. + +Password + The password of the user that will be used for authentication against the Jira API. + +Verify SSL + Whether to verify SSL when connecting to the Jira API (this is ``True`` by default). diff --git a/docs/apache-airflow-providers-atlassian-jira/index.rst b/docs/apache-airflow-providers-atlassian-jira/index.rst index f7ccd801c6469..b22e8c9fb69cc 100644 --- a/docs/apache-airflow-providers-atlassian-jira/index.rst +++ b/docs/apache-airflow-providers-atlassian-jira/index.rst @@ -34,6 +34,7 @@ :maxdepth: 1 :caption: Guides + Connection types Notifications .. toctree:: diff --git a/tests/providers/atlassian/jira/hooks/test_jira.py b/tests/providers/atlassian/jira/hooks/test_jira.py index 930767fb68c87..f3a9888cc0bd3 100644 --- a/tests/providers/atlassian/jira/hooks/test_jira.py +++ b/tests/providers/atlassian/jira/hooks/test_jira.py @@ -21,32 +21,79 @@ import pytest +from airflow.exceptions import AirflowProviderDeprecationWarning from airflow.models import Connection from airflow.providers.atlassian.jira.hooks.jira import JiraHook from airflow.utils import db pytestmark = pytest.mark.db_test - jira_client_mock = Mock(name="jira_client") class TestJiraHook: + depcrecation_message = ( + "Extra parameter `verify` using str is deprecated and will be removed " + "in a future release. Please use `verify` using bool instead." + ) + conn_id = "jira_default" + conn_id_with_str_verify = "jira_default_with_str" + conn_type = "jira" + host = "https://localhost/jira/" + port = 443 + login = "user" + password = "password" + proxies = None + def setup_method(self): db.merge_conn( Connection( - conn_id="jira_default", + conn_id=self.conn_id, + conn_type="jira", + host="https://localhost/jira/", + port=443, + login="user", + password="password", + extra='{"verify": false, "project": "AIRFLOW"}', + ) + ) + db.merge_conn( + Connection( + conn_id=self.conn_id_with_str_verify, conn_type="jira", host="https://localhost/jira/", port=443, + login="user", + password="password", extra='{"verify": "False", "project": "AIRFLOW"}', ) ) @patch("airflow.providers.atlassian.jira.hooks.jira.Jira", autospec=True, return_value=jira_client_mock) def test_jira_client_connection(self, jira_mock): - jira_hook = JiraHook() + jira_hook = JiraHook(proxies=self.proxies) + + jira_mock.assert_called_once_with( + url=self.host, + username=self.login, + password=self.password, + verify_ssl=False, + proxies=self.proxies, + ) + assert isinstance(jira_hook.client, Mock) + assert jira_hook.client.name == jira_mock.return_value.name + + @patch("airflow.providers.atlassian.jira.hooks.jira.Jira", autospec=True, return_value=jira_client_mock) + def test_jira_client_connection_with_str(self, jira_mock): + with pytest.warns(AirflowProviderDeprecationWarning, match=self.depcrecation_message): + jira_hook = JiraHook(jira_conn_id=self.conn_id_with_str_verify, proxies=self.proxies) - assert jira_mock.called + jira_mock.assert_called_once_with( + url=self.host, + username=self.login, + password=self.password, + verify_ssl=False, + proxies=self.proxies, + ) assert isinstance(jira_hook.client, Mock) assert jira_hook.client.name == jira_mock.return_value.name