Repository: python-poetry/poetry

Issue:
How can I set repository url config only by environment variables?
<!--
  Hi there! Thank you for discovering and submitting an issue.

  Before you submit this; let's make sure of a few things.
  Please make sure the following boxes are ticked if they are correct.
  If not, please try and fulfill these first.
-->

<!-- Checked checkbox should look like this: [x] -->
- [x] I am on the [latest](https://github.com/python-poetry/poetry/releases/latest) Poetry version.
- [x] I have searched the [issues](https://github.com/python-poetry/poetry/issues) of this repo and believe that this is not a duplicate.
- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

<!--
  Once those are done, if you're able to fill in the following list with your information,
  it'd be very helpful to whoever handles the issue.
-->

- **OS version and name**: macOS Catalina 10.15.1
- **Poetry version**: Poetry version 1.0.0
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: https://github.com/emoji-gen/ecode-py/blob/2a1cd36bd3b3e4cf2fae5340a2376f3292db151c/pyproject.toml

## Issue
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->

Hello. I tried to publish my project to testpypi, but it failed.
I used only environment variables to configure Poetry. I guess it is cause of failure.

How can I set configuration to publish to custom repository only by environment variables?
The following are the details.

```shell
$ rm -rf dist/
$ poetry build -f wheel
Building ecode (0.1.1)
 - Building wheel
 - Built ecode-0.1.1-py3-none-any.whl
$ set -x POETRY_REPOSITORIES_TESTPYPI https://test.pypi.org/legacy/
$ set -x POETRY_HTTP_BASIC_TESTPYPI_USERNAME pine
$ set -x POETRY_HTTP_BASIC_TESTPYPI_PASSWORD XXX
$ poetry publish -r testpypi -vvv

Publishing ecode (0.1.1) to testpypi

[TypeError]
string indices must be integers

Traceback (most recent call last):
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/console_application.py", line 131, in run
    status_code = command.handle(parsed_args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 120, in handle
    status_code = self._do_handle(args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 171, in _do_handle
    return getattr(handler, handler_method)(args, io, self)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/cleo/commands/command.py", line 92, in wrap_handle
    return self.handle()
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/console/commands/publish.py", line 76, in handle
    publisher.publish(
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/masonry/publishing/publisher.py", line 59, in publish
    url = repository["url"]


$ set -e POETRY_REPOSITORIES_TESTPYPI # Erase the variable
$ set -x POETRY_REPOSITORIES_TESTPYPI_URL https://test.pypi.org/legacy/
$ poetry publish -r testpypi -vvv

Publishing ecode (0.1.1) to testpypi

[NonExistentKey]
'Key "url" does not exist.'

Traceback (most recent call last):
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/console_application.py", line 131, in run
    status_code = command.handle(parsed_args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 120, in handle
    status_code = self._do_handle(args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 171, in _do_handle
    return getattr(handler, handler_method)(args, io, self)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/cleo/commands/command.py", line 92, in wrap_handle
    return self.handle()
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/console/commands/publish.py", line 76, in handle
    publisher.publish(
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/masonry/publishing/publisher.py", line 59, in publish
    url = repository["url"]
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/tomlkit/items.py", line 1008, in __getitem__
    return self._value[key]
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/tomlkit/container.py", line 524, in __getitem__
    raise NonExistentKey(key)
```

I used Python 3.8.0 with pyenv, and fish shell 3.0.2. Thank you.
How can I set repository url config only by environment variables?
<!--
  Hi there! Thank you for discovering and submitting an issue.

  Before you submit this; let's make sure of a few things.
  Please make sure the following boxes are ticked if they are correct.
  If not, please try and fulfill these first.
-->

<!-- Checked checkbox should look like this: [x] -->
- [x] I am on the [latest](https://github.com/python-poetry/poetry/releases/latest) Poetry version.
- [x] I have searched the [issues](https://github.com/python-poetry/poetry/issues) of this repo and believe that this is not a duplicate.
- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

<!--
  Once those are done, if you're able to fill in the following list with your information,
  it'd be very helpful to whoever handles the issue.
-->

- **OS version and name**: macOS Catalina 10.15.1
- **Poetry version**: Poetry version 1.0.0
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: https://github.com/emoji-gen/ecode-py/blob/2a1cd36bd3b3e4cf2fae5340a2376f3292db151c/pyproject.toml

## Issue
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->

Hello. I tried to publish my project to testpypi, but it failed.
I used only environment variables to configure Poetry. I guess it is cause of failure.

How can I set configuration to publish to custom repository only by environment variables?
The following are the details.

```shell
$ rm -rf dist/
$ poetry build -f wheel
Building ecode (0.1.1)
 - Building wheel
 - Built ecode-0.1.1-py3-none-any.whl
$ set -x POETRY_REPOSITORIES_TESTPYPI https://test.pypi.org/legacy/
$ set -x POETRY_HTTP_BASIC_TESTPYPI_USERNAME pine
$ set -x POETRY_HTTP_BASIC_TESTPYPI_PASSWORD XXX
$ poetry publish -r testpypi -vvv

Publishing ecode (0.1.1) to testpypi

[TypeError]
string indices must be integers

Traceback (most recent call last):
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/console_application.py", line 131, in run
    status_code = command.handle(parsed_args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 120, in handle
    status_code = self._do_handle(args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 171, in _do_handle
    return getattr(handler, handler_method)(args, io, self)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/cleo/commands/command.py", line 92, in wrap_handle
    return self.handle()
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/console/commands/publish.py", line 76, in handle
    publisher.publish(
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/masonry/publishing/publisher.py", line 59, in publish
    url = repository["url"]


$ set -e POETRY_REPOSITORIES_TESTPYPI # Erase the variable
$ set -x POETRY_REPOSITORIES_TESTPYPI_URL https://test.pypi.org/legacy/
$ poetry publish -r testpypi -vvv

Publishing ecode (0.1.1) to testpypi

[NonExistentKey]
'Key "url" does not exist.'

Traceback (most recent call last):
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/console_application.py", line 131, in run
    status_code = command.handle(parsed_args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 120, in handle
    status_code = self._do_handle(args, io)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/clikit/api/command/command.py", line 171, in _do_handle
    return getattr(handler, handler_method)(args, io, self)
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/cleo/commands/command.py", line 92, in wrap_handle
    return self.handle()
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/console/commands/publish.py", line 76, in handle
    publisher.publish(
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/poetry/masonry/publishing/publisher.py", line 59, in publish
    url = repository["url"]
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/tomlkit/items.py", line 1008, in __getitem__
    return self._value[key]
  File "/Users/pine/.anyenv/envs/pyenv/versions/3.8.0/lib/python3.8/site-packages/tomlkit/container.py", line 524, in __getitem__
    raise NonExistentKey(key)
```

I used Python 3.8.0 with pyenv, and fish shell 3.0.2. Thank you.


Discussion:

Resolving patch:
diff --git a/poetry/masonry/publishing/publisher.py b/poetry/masonry/publishing/publisher.py
--- a/poetry/masonry/publishing/publisher.py
+++ b/poetry/masonry/publishing/publisher.py
@@ -49,16 +49,12 @@ def publish(self, repository_name, username, password, cert=None, client_cert=No
             repository_name = "pypi"
         else:
             # Retrieving config information
-            repository = self._poetry.config.get(
-                "repositories.{}".format(repository_name)
-            )
-            if repository is None:
+            url = self._poetry.config.get("repositories.{}.url".format(repository_name))
+            if url is None:
                 raise RuntimeError(
                     "Repository {} is not defined".format(repository_name)
                 )
 
-            url = repository["url"]
-
         if not (username and password):
             # Check if we have a token first
             token = self._password_manager.get_pypi_token(repository_name)


Test patch:
diff --git a/tests/masonry/publishing/test_publisher.py b/tests/masonry/publishing/test_publisher.py
--- a/tests/masonry/publishing/test_publisher.py
+++ b/tests/masonry/publishing/test_publisher.py
@@ -1,3 +1,5 @@
+import os
+
 import pytest
 
 from poetry.factory import Factory
@@ -119,3 +121,21 @@ def test_publish_uses_client_cert(fixture_dir, mocker, config):
         ("https://foo.bar",),
         {"cert": None, "client_cert": Path(client_cert)},
     ] == uploader_upload.call_args
+
+
+def test_publish_read_from_environment_variable(fixture_dir, environ, mocker, config):
+    os.environ["POETRY_REPOSITORIES_FOO_URL"] = "https://foo.bar"
+    os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar"
+    os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz"
+    uploader_auth = mocker.patch("poetry.masonry.publishing.uploader.Uploader.auth")
+    uploader_upload = mocker.patch("poetry.masonry.publishing.uploader.Uploader.upload")
+    poetry = Factory().create_poetry(fixture_dir("sample_project"))
+    publisher = Publisher(poetry, NullIO())
+
+    publisher.publish("foo", None, None)
+
+    assert [("bar", "baz")] == uploader_auth.call_args
+    assert [
+        ("https://foo.bar",),
+        {"cert": None, "client_cert": None},
+    ] == uploader_upload.call_args