Skip to content

Commit 163a408

Browse files
authored
Relax requirement for specification of Git provider for Repos (#385)
* Relax requirement for specification of Git provider for Repos Before this PR, the `--provider` option was required, but in many cases we can guess the provider ID from the URL (for hosted providers as Gitlab, GitHub, etc.) - this PR is making `--provider` option not required, but if we can't guess Git provider, it will error out. * addressing review comments * add support for AWS CodeCommit repositories
1 parent e427730 commit 163a408

File tree

5 files changed

+68
-4
lines changed

5 files changed

+68
-4
lines changed

databricks_cli/repos/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ def list_repos_cli(api_client, path_prefix, next_page_token):
5252
@click.command(context_settings=CONTEXT_SETTINGS,
5353
short_help='Create a repo and link it to the given remote Git repo')
5454
@click.option('--url', required=True, help="URL of the remote Git repo")
55-
@click.option('--provider', required=True, help="Git provider (case insensitive)")
55+
@click.option('--provider',
56+
help="Git provider (case insensitive). Required if it couldn't be detected from "
57+
"host name")
5658
@click.option('--path', help="Desired workspace path of the repo object")
5759
@debug_option
5860
@profile_option

databricks_cli/sdk/service.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
# limitations under the License.
2525
#
2626
import os
27+
import re
28+
29+
from six.moves.urllib.parse import urlparse
2730

2831

2932
class JobsService(object):
@@ -1075,10 +1078,35 @@ def stop(self, pipeline_id=None, headers=None):
10751078

10761079
return self.client.perform_query('POST', '/pipelines/{pipeline_id}/stop'.format(pipeline_id=pipeline_id),
10771080
data=_data, headers=headers)
1081+
1082+
10781083
class ReposService(object):
1084+
__git_providers__ = {
1085+
"github.com": "gitHub",
1086+
"dev.azure.com": "azureDevOpsServices",
1087+
"gitlab.com": "gitLab",
1088+
"bitbucket.org": "bitbucketCloud"
1089+
}
1090+
__aws_code_commit_regexp__ = re.compile(r"^git-codecommit\.[^.]+\.amazonaws.com$")
1091+
10791092
def __init__(self, client):
10801093
self.client = client
10811094

1095+
@staticmethod
1096+
def detect_repo_provider(url):
1097+
provider = None
1098+
try:
1099+
netloc = urlparse(url).netloc
1100+
idx = netloc.rfind("@")
1101+
if idx != -1:
1102+
netloc = netloc[(idx + 1):]
1103+
provider = ReposService.__git_providers__.get(netloc.lower())
1104+
if provider is None and ReposService.__aws_code_commit_regexp__.match(netloc):
1105+
provider = "awsCodeCommit"
1106+
except:
1107+
pass
1108+
return provider
1109+
10821110
def list_repos(self, path_prefix=None, next_page_token=None, headers=None):
10831111
_data = {}
10841112
if path_prefix is not None:
@@ -1090,27 +1118,35 @@ def list_repos(self, path_prefix=None, next_page_token=None, headers=None):
10901118
def get_repo(self, id, headers=None):
10911119
_data = {}
10921120

1093-
return self.client.perform_query('GET', '/repos/{id}'.format(id=id), data=_data, headers=headers)
1121+
return self.client.perform_query('GET', '/repos/{id}'.format(id=id),
1122+
data=_data, headers=headers)
10941123

10951124
def update_repo(self, id, branch=None, tag=None, headers=None):
10961125
_data = {}
10971126
if branch is not None:
10981127
_data['branch'] = branch
10991128
if tag is not None:
11001129
_data['tag'] = tag
1101-
return self.client.perform_query('PATCH', '/repos/{id}'.format(id=id), data=_data, headers=headers)
1130+
return self.client.perform_query('PATCH', '/repos/{id}'.format(id=id),
1131+
data=_data, headers=headers)
11021132

11031133
def create_repo(self, url, provider, path=None, headers=None):
11041134
_data = {}
11051135
if url is not None:
11061136
_data['url'] = url
1137+
if provider is None or provider.trim() == "":
1138+
provider = self.detect_repo_provider(url)
11071139
if provider is not None:
11081140
_data['provider'] = provider
1141+
else:
1142+
raise ValueError("The Git provider parameter wasn't specified and we can't detect it "
1143+
"from URL. Please pass 'provider' option")
11091144
if path is not None:
11101145
_data['path'] = path
11111146
return self.client.perform_query('POST', '/repos', data=_data, headers=headers)
11121147

11131148
def delete_repo(self, id, headers=None):
11141149
_data = {}
11151150

1116-
return self.client.perform_query('DELETE', '/repos/{id}'.format(id=id), data=_data, headers=headers)
1151+
return self.client.perform_query('DELETE', '/repos/{id}'.format(id=id),
1152+
data=_data, headers=headers)

tests/repos/test_api.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,9 @@ def test_get_id_other_error(self, repos_api_with_ws_service):
8888
side_effect=requests.exceptions.HTTPError(response=response))
8989
with pytest.raises(RuntimeError):
9090
repos_api_with_ws_service.get_repo_id(TEST_PATH)
91+
92+
93+
class TestCreateRepo(object):
94+
def test_get(self, repos_api_with_ws_service):
95+
with pytest.raises(ValueError):
96+
repos_api_with_ws_service.create("https://github1.com/user/repo.git", None, None)

tests/repos/test_cli.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ def test_create_validation(repos_api_mock):
7575
)
7676

7777

78+
@provide_conf
79+
def test_create_validation_partial(repos_api_mock):
80+
runner = CliRunner()
81+
runner.invoke(cli.create_repo_cli,
82+
["--url", TEST_URL])
83+
repos_api_mock.create.assert_called_once_with(
84+
TEST_URL,
85+
None,
86+
None,
87+
)
88+
89+
7890
@provide_conf
7991
def test_get_validation(repos_api_mock):
8092
runner = CliRunner()

tests/sdk/test_api_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import requests
2727
import requests_mock
2828

29+
from databricks_cli.sdk import ReposService
2930
from databricks_cli.sdk.api_client import ApiClient
3031

3132

@@ -123,3 +124,10 @@ def test_api_client_url_parsing():
123124
# databricks_cli.configure.cli
124125
client = ApiClient(host='http://databricks.com')
125126
assert client.get_url('') == 'http://databricks.com/api/2.0'
127+
128+
129+
def test_repos_provider_detection():
130+
assert ReposService.detect_repo_provider("https://github.com/org/repo.git") == "gitHub"
131+
assert ReposService.detect_repo_provider(
132+
"https://git-codecommit.us-east-2.amazonaws.com/v1/repos/MyDemoRepo") == "awsCodeCommit"
133+
assert ReposService.detect_repo_provider("https://github1.com/org/repo.git") is None

0 commit comments

Comments
 (0)