Repository: pypi/warehouse

Issue:
"File already exists." Error could use help links
#2670 brings to light that our error when uploading a filename which has already been used, but no longer exists is unclear.

```
HTTPError: 400 Client Error: File already exists. for url: https://upload.pypi.org/legacy/
```

Here are the two scenarios and messaging I believe would be more helpful. We'd need to create the help entry for `https://pypi.org/help/#file-name-reuse` as well.

- Filename has been used, file exists:

```HTTPError: 400 Client Error: File already exists, see https://pypi.org/help/#file-name-reuse. for url: https://upload.pypi.org/legacy/```

- Filename has been used, file no longer exists:

```HTTPError: 400 Client Error: Filename cannot be reused, see https://pypi.org/help/#file-name-reuse. for url: https://upload.pypi.org/legacy/```


Discussion:

Resolving patch:
diff --git a/warehouse/forklift/legacy.py b/warehouse/forklift/legacy.py
--- a/warehouse/forklift/legacy.py
+++ b/warehouse/forklift/legacy.py
@@ -1027,7 +1027,13 @@ def file_upload(request):
         if is_duplicate:
             return Response()
         elif is_duplicate is not None:
-            raise _exc_with_message(HTTPBadRequest, "File already exists.")
+            raise _exc_with_message(
+                HTTPBadRequest, "File already exists. "
+                                "See " +
+                                request.route_url(
+                                    'help', _anchor='file-name-reuse'
+                                )
+            )
 
         # Check to see if the file that was uploaded exists in our filename log
         if (request.db.query(
@@ -1037,7 +1043,10 @@ def file_upload(request):
             raise _exc_with_message(
                 HTTPBadRequest,
                 "This filename has previously been used, you should use a "
-                "different version.",
+                "different version. "
+                "See " + request.route_url(
+                    'help', _anchor='file-name-reuse'
+                ),
             )
 
         # Check to see if uploading this file would create a duplicate sdist


Test patch:
diff --git a/tests/unit/forklift/test_legacy.py b/tests/unit/forklift/test_legacy.py
--- a/tests/unit/forklift/test_legacy.py
+++ b/tests/unit/forklift/test_legacy.py
@@ -1615,16 +1615,23 @@ def test_upload_fails_with_previously_used_filename(self, pyramid_config,
         })
 
         db_request.db.add(Filename(filename=filename))
+        db_request.route_url = pretend.call_recorder(
+            lambda route, **kw: "/the/help/url/"
+        )
 
         with pytest.raises(HTTPBadRequest) as excinfo:
             legacy.file_upload(db_request)
 
         resp = excinfo.value
 
+        assert db_request.route_url.calls == [
+            pretend.call('help', _anchor='file-name-reuse')
+        ]
         assert resp.status_code == 400
         assert resp.status == (
             "400 This filename has previously been used, you should use a "
-            "different version."
+            "different version. "
+            "See /the/help/url/"
         )
 
     def test_upload_noop_with_existing_filename_same_content(self,
@@ -1722,14 +1729,22 @@ def test_upload_fails_with_existing_filename_diff_content(self,
                 ),
             ),
         )
-
+        db_request.route_url = pretend.call_recorder(
+            lambda route, **kw: "/the/help/url/"
+        )
         with pytest.raises(HTTPBadRequest) as excinfo:
             legacy.file_upload(db_request)
 
         resp = excinfo.value
 
+        assert db_request.route_url.calls == [
+            pretend.call('help', _anchor='file-name-reuse')
+        ]
         assert resp.status_code == 400
-        assert resp.status == "400 File already exists."
+        assert resp.status == (
+            "400 File already exists. "
+            "See /the/help/url/"
+        )
 
     def test_upload_fails_with_wrong_filename(self, pyramid_config,
                                               db_request):