Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d56e85d

Browse filesBrowse files
authored
feat(repository): add support for TWINE_CERT (python-semantic-release#522)
Fixes python-semantic-release#521
1 parent 5cbdad2 commit d56e85d
Copy full SHA for d56e85d

File tree

3 files changed

+33
-4
lines changed
Filter options

3 files changed

+33
-4
lines changed

‎docs/envvars.rst

Copy file name to clipboardExpand all lines: docs/envvars.rst
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,7 @@ Custom repository (package index) URL to upload the package to.
159159
Takes precedence over :ref:`config-repository_url`
160160

161161
See :ref:`automatic-dist-upload` for more about uploads to custom repositories.
162+
163+
``TWINE_CERT``
164+
------------------
165+
Path to alternative CA bundle to use for SSL verification to repository. `See here for more information <https://twine.readthedocs.io/en/stable/>`

‎semantic_release/repository.py

Copy file name to clipboardExpand all lines: semantic_release/repository.py
+8-3Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
"""
33
import logging
44
import os
5-
from dataclasses import InitVar
6-
from dataclasses import asdict as dataclass_asdict
7-
from dataclasses import dataclass, field
5+
from dataclasses import InitVar, asdict as dataclass_asdict, dataclass, field
86
from pathlib import Path
97
from typing import Any, Dict, List, Optional
108

@@ -126,6 +124,13 @@ def _create_twine_settings(self, addon_kwargs: Dict[str, Any]) -> TwineSettings:
126124
pass them to Twine which then validates and loads the config.
127125
"""
128126
params = {name: val for name, val in dataclass_asdict(self).items() if val}
127+
cacert = os.environ.get("TWINE_CERT", None)
128+
if cacert:
129+
if not Path(cacert).is_file():
130+
raise ImproperConfigurationError(
131+
f"TWINE_CERT env variable set, but file does not exist. Value: {cacert}"
132+
)
133+
params["cacert"] = cacert
129134
settings = TwineSettings(**params, **addon_kwargs)
130135

131136
return settings

‎tests/test_repository.py

Copy file name to clipboardExpand all lines: tests/test_repository.py
+21-1Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,19 @@ def test_repo_with_custom_repo_url_from_env(mock_handle_creds):
174174
{
175175
"REPOSITORY_USERNAME": "repo-username",
176176
"REPOSITORY_PASSWORD": "repo-password",
177+
"TWINE_CERT": "cert_bundle.crt",
177178
},
178179
)
179-
def test_upload_with_custom_settings(mock_upload):
180+
@mock.patch("semantic_release.repository.Path.is_file", return_value=True)
181+
def test_upload_with_custom_settings(mock_is_file, mock_upload):
180182
repo = ArtifactRepo(Path("custom-dist"))
181183
repo.upload(
182184
noop=False, verbose=True, skip_existing=True, comment="distribution comment"
183185
)
184186
settings = mock_upload.call_args[1]["upload_settings"]
185187
assert isinstance(settings.auth, auth.Private)
186188
assert settings.comment == "distribution comment"
189+
assert settings.cacert == "cert_bundle.crt"
187190
assert settings.username == "repo-username"
188191
assert settings.password == "repo-password"
189192
assert settings.repository_config["repository"] == "https://custom-repo"
@@ -192,6 +195,23 @@ def test_upload_with_custom_settings(mock_upload):
192195
assert mock_upload.called
193196

194197

198+
@mock.patch.dict(
199+
"os.environ",
200+
{
201+
"TWINE_CERT": "cert_bundle.crt",
202+
},
203+
)
204+
@mock.patch("semantic_release.repository.Path.is_file", return_value=False)
205+
@mock.patch.object(ArtifactRepo, "_handle_credentials_init")
206+
def test_upload_with_invalid_twine_cert(mock_is_file, mock_handle_creds):
207+
repo = ArtifactRepo(Path("custom-dist"))
208+
209+
with pytest.raises(ImproperConfigurationError) as ex:
210+
repo.upload(noop=False, verbose=True, skip_existing=True)
211+
212+
assert "TWINE_CERT env variable set, but file does not exist" in str(ex.value)
213+
214+
195215
@mock.patch.object(ArtifactRepo, "_handle_credentials_init")
196216
@mock.patch("semantic_release.repository.twine_upload")
197217
def test_upload_with_noop(mock_upload, mock_handle_creds):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.