Skip to content
Permalink
Browse files

Add cli options to publish for cert and custom ca

  • Loading branch information
Caligatio committed Aug 25, 2019
1 parent 07aba89 commit 35577b0175e596413fa41ebb32db9f4748f26c5e
@@ -1,5 +1,7 @@
from cleo import option

from poetry.utils._compat import Path

from .command import Command


@@ -14,6 +16,18 @@ class PublishCommand(Command):
),
option("username", "u", "The username to access the repository.", flag=False),
option("password", "p", "The password to access the repository.", flag=False),
option(
"custom-ca",
None,
"Certificate authority to access the repository.",
flag=False,
),
option(
"client-cert",
None,
"Client certificate to access the repository.",
flag=False,
),
option("build", None, "Build the package before publishing."),
]

@@ -57,6 +71,15 @@ def handle(self):

self.line("")

custom_ca = Path(self.option("custom-ca")) if self.option("custom-ca") else None
client_cert = (
Path(self.option("client-cert")) if self.option("client-cert") else None
)

publisher.publish(
self.option("repository"), self.option("username"), self.option("password")
self.option("repository"),
self.option("username"),
self.option("password"),
custom_ca,
client_cert,
)
@@ -23,7 +23,9 @@ def __init__(self, poetry, io):
def files(self):
return self._uploader.files

def publish(self, repository_name, username, password):
def publish(
self, repository_name, username, password, custom_ca=None, client_cert=None
):
if repository_name:
self._io.write_line(
"Publishing <info>{}</info> (<comment>{}</comment>) "
@@ -74,17 +76,21 @@ def publish(self, repository_name, username, password):
username = auth[0]
password = auth[1]

# Requesting missing credentials
if username is None:
username = self._io.ask("Username:")
resolved_client_cert = client_cert or get_client_cert(
self._poetry.config, repository_name
)
# Requesting missing credentials but only if there is not a client cert defined.
if not resolved_client_cert:
if username is None:
username = self._io.ask("Username:")

if password is None:
password = self._io.ask_hidden("Password:")
if password is None:
password = self._io.ask_hidden("Password:")

self._uploader.auth(username, password)

return self._uploader.upload(
url,
custom_ca=get_custom_ca(self._poetry.config, repository_name),
client_cert=get_client_cert(self._poetry.config, repository_name),
custom_ca=custom_ca or get_custom_ca(self._poetry.config, repository_name),
client_cert=resolved_client_cert,
)
@@ -1,3 +1,6 @@
from poetry.utils._compat import Path


def test_publish_returns_non_zero_code_for_upload_errors(app, app_tester, http):
http.register_uri(
http.POST, "https://upload.pypi.org/legacy/", status=400, body="Bad Request"
@@ -16,3 +19,22 @@ def test_publish_returns_non_zero_code_for_upload_errors(app, app_tester, http):
"""

assert app_tester.io.fetch_output() == expected


def test_publish_with_custom_ca(app_tester, mocker):
publisher_publish = mocker.patch("poetry.masonry.publishing.Publisher.publish")

app_tester.execute("publish --custom-ca path/to/ca.pem")

assert [
(None, None, None, Path("path/to/ca.pem"), None)
] == publisher_publish.call_args


def test_publish_with_client_cert(app_tester, mocker):
publisher_publish = mocker.patch("poetry.masonry.publishing.Publisher.publish")

app_tester.execute("publish --client-cert path/to/client.pem")
assert [
(None, None, None, None, Path("path/to/client.pem"))
] == publisher_publish.call_args
@@ -82,20 +82,18 @@ def test_publish_uses_custom_ca(fixture_dir, mocker, config):
uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
poetry = Poetry.create(fixture_dir("sample_project"))
poetry._config = config
# Adding the empty string for username/password is a bit of a hack but otherwise it will prompt for them
# username and password are optional but there is no good way of specifying a lack of them other than empty string
poetry.config.merge(
{
"repositories": {"foo": {"url": "https://foo.bar"}},
"http-basic": {"foo": {"username": "", "password": ""}},
"http-basic": {"foo": {"username": "foo", "password": "bar"}},
"certificates": {"foo": {"custom-ca": custom_ca}},
}
)
publisher = Publisher(poetry, NullIO())

publisher.publish("foo", None, None)

assert [("", "")] == uploader_auth.call_args
assert [("foo", "bar")] == uploader_auth.call_args
assert [
("https://foo.bar",),
{"custom_ca": Path(custom_ca), "client_cert": None},
@@ -104,24 +102,19 @@ def test_publish_uses_custom_ca(fixture_dir, mocker, config):

def test_publish_uses_client_cert(fixture_dir, mocker, config):
client_cert = "path/to/client.pem"
uploader_auth = mocker.patch("poetry.masonry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
poetry = Poetry.create(fixture_dir("sample_project"))
poetry._config = config
# Adding the empty string for username/password is a bit of a hack but otherwise it will prompt for them
# username and password are optional but there is no good way of specifying a lack of them other than empty string
poetry.config.merge(
{
"repositories": {"foo": {"url": "https://foo.bar"}},
"http-basic": {"foo": {"username": "", "password": ""}},
"certificates": {"foo": {"client-cert": client_cert}},
}
)
publisher = Publisher(poetry, NullIO())

publisher.publish("foo", None, None)

assert [("", "")] == uploader_auth.call_args
assert [
("https://foo.bar",),
{"custom_ca": None, "client_cert": Path(client_cert)},

0 comments on commit 35577b0

Please sign in to comment.
You can’t perform that action at this time.