Skip to content

Commit 461bac0

Browse files
authored
Merge pull request #203 from sigmavirus24/cli-repo-url
Specify the Repository URL with --repository-url
2 parents 26a7c44 + c9d8cf7 commit 461bac0

File tree

6 files changed

+105
-27
lines changed

6 files changed

+105
-27
lines changed

docs/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ Changelog
1616

1717
- Password will default to ``TWINE_PASSWORD``
1818

19+
* :feature:`166` Allow the Repository URL to be provided on the command-line
20+
(``--repository-url``) or via an environment variable
21+
(``TWINE_REPOSITORY_URL``).
22+
1923
* :release:`1.7.4 <2016-07-09>`
2024

2125
* Correct a packaging error.

tests/test_upload.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,13 @@ def test_get_config_old_format(tmpdir):
8282
upload.upload(dists=dists, repository="pypi", sign=None, identity=None,
8383
username=None, password=None, comment=None,
8484
cert=None, client_cert=None,
85-
sign_with=None, config_file=pypirc, skip_existing=False)
85+
sign_with=None, config_file=pypirc, skip_existing=False,
86+
repository_url=None,
87+
)
8688
except KeyError as err:
8789
assert err.args[0] == (
88-
"Missing 'pypi' section from the configuration file.\n"
90+
"Missing 'pypi' section from the configuration file\n"
91+
"or not a complete URL in --repository.\n"
8992
"Maybe you have a out-dated '{0}' format?\n"
9093
"more info: "
9194
"https://docs.python.org/distutils/packageindex.html#pypirc\n"
@@ -130,7 +133,9 @@ def test_skip_upload_respects_skip_existing(monkeypatch):
130133

131134

132135
def test_password_and_username_from_env(monkeypatch):
133-
def none_upload(*args, **kwargs): pass
136+
def none_upload(*args, **kwargs):
137+
pass
138+
134139
replaced_upload = pretend.call_recorder(none_upload)
135140
monkeypatch.setattr(twine.commands.upload, "upload", replaced_upload)
136141
testenv = {"TWINE_USERNAME": "pypiuser",

tests/test_utils.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import pytest
2121

22-
from twine.utils import DEFAULT_REPOSITORY, get_config, get_userpass_value
2322
from twine import utils
2423

2524
import helpers
@@ -38,9 +37,9 @@ def test_get_config(tmpdir):
3837
password = testpassword
3938
"""))
4039

41-
assert get_config(pypirc) == {
40+
assert utils.get_config(pypirc) == {
4241
"pypi": {
43-
"repository": DEFAULT_REPOSITORY,
42+
"repository": utils.DEFAULT_REPOSITORY,
4443
"username": "testuser",
4544
"password": "testpassword",
4645
},
@@ -57,9 +56,9 @@ def test_get_config_no_distutils(tmpdir):
5756
password = testpassword
5857
"""))
5958

60-
assert get_config(pypirc) == {
59+
assert utils.get_config(pypirc) == {
6160
"pypi": {
62-
"repository": DEFAULT_REPOSITORY,
61+
"repository": utils.DEFAULT_REPOSITORY,
6362
"username": "testuser",
6463
"password": "testpassword",
6564
},
@@ -79,9 +78,9 @@ def test_get_config_no_section(tmpdir):
7978
password = testpassword
8079
"""))
8180

82-
assert get_config(pypirc) == {
81+
assert utils.get_config(pypirc) == {
8382
"pypi": {
84-
"repository": DEFAULT_REPOSITORY,
83+
"repository": utils.DEFAULT_REPOSITORY,
8584
"username": "testuser",
8685
"password": "testpassword",
8786
},
@@ -91,23 +90,47 @@ def test_get_config_no_section(tmpdir):
9190
def test_get_config_missing(tmpdir):
9291
pypirc = os.path.join(str(tmpdir), ".pypirc")
9392

94-
assert get_config(pypirc) == {
93+
assert utils.get_config(pypirc) == {
9594
"pypi": {
96-
"repository": DEFAULT_REPOSITORY,
95+
"repository": utils.DEFAULT_REPOSITORY,
9796
"username": None,
9897
"password": None,
9998
},
99+
"pypitest": {
100+
"repository": utils.TEST_REPOSITORY,
101+
"username": None,
102+
"password": None
103+
},
100104
}
101105

102106

107+
def test_get_repository_config_missing(tmpdir):
108+
pypirc = os.path.join(str(tmpdir), ".pypirc")
109+
110+
repository_url = "https://notexisting.python.org/pypi"
111+
exp = {
112+
"repository": repository_url,
113+
"username": None,
114+
"password": None,
115+
}
116+
assert (utils.get_repository_from_config(pypirc, 'foo', repository_url) ==
117+
exp)
118+
exp = {
119+
"repository": utils.DEFAULT_REPOSITORY,
120+
"username": None,
121+
"password": None,
122+
}
123+
assert utils.get_repository_from_config(pypirc, "pypi") == exp
124+
125+
103126
def test_get_config_deprecated_pypirc():
104127
tests_dir = os.path.dirname(os.path.abspath(__file__))
105128
deprecated_pypirc_path = os.path.join(tests_dir, 'fixtures',
106129
'deprecated-pypirc')
107130

108-
assert get_config(deprecated_pypirc_path) == {
131+
assert utils.get_config(deprecated_pypirc_path) == {
109132
"pypi": {
110-
"repository": DEFAULT_REPOSITORY,
133+
"repository": utils.DEFAULT_REPOSITORY,
111134
"username": 'testusername',
112135
"password": 'testpassword',
113136
},
@@ -123,7 +146,7 @@ def test_get_config_deprecated_pypirc():
123146
),
124147
)
125148
def test_get_userpass_value(cli_value, config, key, strategy, expected):
126-
ret = get_userpass_value(cli_value, config, key, strategy)
149+
ret = utils.get_userpass_value(cli_value, config, key, strategy)
127150
assert ret == expected
128151

129152

twine/commands/register.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424

2525

2626
def register(package, repository, username, password, comment, config_file,
27-
cert, client_cert):
28-
config = utils.get_repository_from_config(config_file, repository)
27+
cert, client_cert, repository_url):
28+
config = utils.get_repository_from_config(
29+
config_file,
30+
repository,
31+
repository_url,
32+
)
2933
config["repository"] = utils.normalize_repository_url(
3034
config["repository"]
3135
)
@@ -63,23 +67,34 @@ def main(args):
6367
parser.add_argument(
6468
"-r", "--repository",
6569
action=utils.EnvironmentDefault,
66-
env='TWINE_REPOSITORY',
70+
env="TWINE_REPOSITORY",
6771
default="pypi",
68-
help="The repository to register the package to (default: "
72+
help="The repository to register the package to. Can be a section in "
73+
"the config file or a full URL to the repository (default: "
6974
"%(default)s)",
7075
)
76+
parser.add_argument(
77+
"--repository-url",
78+
action=utils.EnvironmentDefault,
79+
env="TWINE_REPOSITORY_URL",
80+
default=None,
81+
required=False,
82+
help="The repository URL to upload the package to. This can be "
83+
"specified with --repository because it will be used if there is "
84+
"no configuration for the value passed to --repository."
85+
)
7186
parser.add_argument(
7287
"-u", "--username",
7388
action=utils.EnvironmentDefault,
74-
env='TWINE_USERNAME',
89+
env="TWINE_USERNAME",
7590
required=False, help="The username to authenticate to the repository "
7691
"as (can also be set via %(env)s environment "
7792
"variable)",
7893
)
7994
parser.add_argument(
8095
"-p", "--password",
8196
action=utils.EnvironmentDefault,
82-
env='TWINE_PASSWORD',
97+
env="TWINE_PASSWORD",
8398
required=False, help="The password to authenticate to the repository "
8499
"with (can also be set via %(env)s environment "
85100
"variable)",

twine/commands/upload.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ def skip_upload(response, skip_existing, package):
7272

7373

7474
def upload(dists, repository, sign, identity, username, password, comment,
75-
sign_with, config_file, skip_existing, cert, client_cert):
75+
sign_with, config_file, skip_existing, cert, client_cert,
76+
repository_url):
7677
# Check that a nonsensical option wasn't given
7778
if not sign and identity:
7879
raise ValueError("sign must be given along with identity")
@@ -85,7 +86,11 @@ def upload(dists, repository, sign, identity, username, password, comment,
8586
)
8687
uploads = [i for i in dists if not i.endswith(".asc")]
8788

88-
config = utils.get_repository_from_config(config_file, repository)
89+
config = utils.get_repository_from_config(
90+
config_file,
91+
repository,
92+
repository_url,
93+
)
8994

9095
config["repository"] = utils.normalize_repository_url(
9196
config["repository"]
@@ -152,7 +157,19 @@ def main(args):
152157
action=utils.EnvironmentDefault,
153158
env="TWINE_REPOSITORY",
154159
default="pypi",
155-
help="The repository to upload the files to (default: %(default)s)",
160+
help="The repository to register the package to. Can be a section in "
161+
"the config file or a full URL to the repository (default: "
162+
"%(default)s)",
163+
)
164+
parser.add_argument(
165+
"--repository-url",
166+
action=utils.EnvironmentDefault,
167+
env="TWINE_REPOSITORY_URL",
168+
default=None,
169+
required=False,
170+
help="The repository URL to upload the package to. This can be "
171+
"specified with --repository because it will be used if there is "
172+
"no configuration for the value passed to --repository."
156173
)
157174
parser.add_argument(
158175
"-s", "--sign",

twine/utils.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141

4242
DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/"
43+
TEST_REPOSITORY = "https://test.pypi.org/legacy/"
4344

4445

4546
def get_config(path="~/.pypirc"):
@@ -50,7 +51,11 @@ def get_config(path="~/.pypirc"):
5051
return {"pypi": {"repository": DEFAULT_REPOSITORY,
5152
"username": None,
5253
"password": None
53-
}
54+
},
55+
"pypitest": {"repository": TEST_REPOSITORY,
56+
"username": None,
57+
"password": None
58+
},
5459
}
5560

5661
# Parse the rc file
@@ -94,13 +99,22 @@ def get_config(path="~/.pypirc"):
9499
return config
95100

96101

97-
def get_repository_from_config(config_file, repository):
102+
def get_repository_from_config(config_file, repository, repository_url=None):
98103
# Get our config from the .pypirc file
99104
try:
100105
return get_config(config_file)[repository]
101106
except KeyError:
107+
if repository_url and "://" in repository_url:
108+
# assume that the repsoitory is actually an URL and just sent
109+
# them a dummy with the repo set
110+
return {
111+
"repository": repository_url,
112+
"username": None,
113+
"password": None,
114+
}
102115
msg = (
103-
"Missing '{repo}' section from the configuration file.\n"
116+
"Missing '{repo}' section from the configuration file\n"
117+
"or not a complete URL in --repository.\n"
104118
"Maybe you have a out-dated '{cfg}' format?\n"
105119
"more info: "
106120
"https://docs.python.org/distutils/packageindex.html#pypirc\n"

0 commit comments

Comments
 (0)