diff --git a/app/blueprints/api/endpoints.py b/app/blueprints/api/endpoints.py
index d71b7e02..461926cf 100644
--- a/app/blueprints/api/endpoints.py
+++ b/app/blueprints/api/endpoints.py
@@ -175,7 +175,9 @@ def create_release(token, package):
if file is None:
error(400, "Missing 'file' in multipart body")
- return api_create_zip_release(token, package, data["title"], file)
+ commit_hash = data.get("commit")
+
+ return api_create_zip_release(token, package, data["title"], file, None, None, "API", commit_hash)
else:
error(400, "Unknown release-creation method. Specify the method or provide a file.")
diff --git a/app/blueprints/api/support.py b/app/blueprints/api/support.py
index 0f09b99e..2683637b 100644
--- a/app/blueprints/api/support.py
+++ b/app/blueprints/api/support.py
@@ -54,13 +54,13 @@ def api_create_vcs_release(token: APIToken, package: Package, title: str, ref: s
def api_create_zip_release(token: APIToken, package: Package, title: str, file,
- min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason="API"):
+ min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason="API", commit_hash:str=None):
if not token.canOperateOnPackage(package):
error(403, "API token does not have access to the package")
reason += ", token=" + token.name
- rel = guard(do_create_zip_release)(token.owner, package, title, file, min_v, max_v, reason)
+ rel = guard(do_create_zip_release)(token.owner, package, title, file, min_v, max_v, reason, commit_hash)
return jsonify({
"success": True,
diff --git a/app/flatpages/help/api.md b/app/flatpages/help/api.md
index 95d4f37e..bb78cf41 100644
--- a/app/flatpages/help/api.md
+++ b/app/flatpages/help/api.md
@@ -14,7 +14,16 @@ If there is an error, the response will be JSON similar to the following with a
Successful GET requests will return the resource's information directly as a JSON response.
Other successful results will return a dictionary with `success` equaling true, and
-often other keys with information.
+often other keys with information. For example:
+
+```js
+{
+ "success": true,
+ "release": {
+ /* same as returned by a GET */
+ }
+}
+```
## Authentication
@@ -117,7 +126,8 @@ Supported query parameters:
* `method`: must be `git`.
* `ref`: (Optional) git reference, eg: `master`.
* For zip upload release creation:
- * `file`: multipart file to upload, like ``.
+ * `file`: multipart file to upload, like ``.
+ * `commit`: (Optional) Source Git commit hash, for informational purposes.
* You can set min and max Minetest Versions [using the content's .conf file](/help/package_config/).
* DELETE `/api/packages///releases//` (Delete)
* Requires authentication.
@@ -136,6 +146,11 @@ curl -X POST https://content.minetest.net/api/packages/username/name/releases/ne
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/file.zip
+# Create release from zip upload with commit hash
+curl -X POST https://content.minetest.net/api/packages/username/name/releases/new/ \
+ -H "Authorization: Bearer YOURTOKEN" \
+ -F title="My Release" -F commit="8ef74deec170a8ce789f6055a59d43876d16a7ea" -F file=@path/to/file.zip
+
# Delete release
curl -X DELETE https://content.minetest.net/api/packages/username/name/releases/3/ \
-H "Authorization: Bearer YOURTOKEN"
@@ -169,7 +184,7 @@ curl -X DELETE https://content.minetest.net/api/packages/username/name/releases/
Examples:
```bash
-# Create screenshots
+# Create screenshot
curl -X POST https://content.minetest.net/api/packages/username/name/screenshots/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/screnshot.png
diff --git a/app/logic/releases.py b/app/logic/releases.py
index 7190d1b4..7b1e3c45 100644
--- a/app/logic/releases.py
+++ b/app/logic/releases.py
@@ -15,7 +15,7 @@
# along with this program. If not, see .
-import datetime
+import datetime, re
from celery import uuid
@@ -63,9 +63,15 @@ def do_create_vcs_release(user: User, package: Package, title: str, ref: str,
def do_create_zip_release(user: User, package: Package, title: str, file,
- min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason: str = None):
+ min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason: str = None,
+ commit_hash: str = None):
check_can_create_release(user, package)
+ if commit_hash:
+ commit_hash = commit_hash.lower()
+ if not (len(commit_hash) == 40 and re.match(r"^[0-9a-f]+$", commit_hash)):
+ raise LogicError(400, "Invalid commit hash; it must be a 40 character long base16 string")
+
uploaded_url, uploaded_path = upload_file(file, "zip", "a zip file")
rel = PackageRelease()
@@ -73,6 +79,7 @@ def do_create_zip_release(user: User, package: Package, title: str, file,
rel.title = title
rel.url = uploaded_url
rel.task_id = uuid()
+ rel.commit_hash = commit_hash
rel.min_rel = min_v
rel.max_rel = max_v
db.session.add(rel)