Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
## Version [v0.1.15] - 2025-08-29

### Fixed

* Top-level `.juliabundleignore` files are now correctly handled when using `JuliaHub.appbundle`. ([#99], [#100])
* The `JuliaHub.upload_dataset` now correctly throws a `JuliaHubError` on certain backend errors. ([#103])

## Version [v0.1.14] - 2025-06-11

Expand Down Expand Up @@ -159,6 +160,7 @@ Initial package release.
[v0.1.12]: https://github.com/JuliaComputing/JuliaHub.jl/releases/tag/v0.1.12
[v0.1.13]: https://github.com/JuliaComputing/JuliaHub.jl/releases/tag/v0.1.13
[v0.1.14]: https://github.com/JuliaComputing/JuliaHub.jl/releases/tag/v0.1.14
[v0.1.15]: https://github.com/JuliaComputing/JuliaHub.jl/releases/tag/v0.1.15
[#1]: https://github.com/JuliaComputing/JuliaHub.jl/issues/1
[#2]: https://github.com/JuliaComputing/JuliaHub.jl/issues/2
[#3]: https://github.com/JuliaComputing/JuliaHub.jl/issues/3
Expand Down Expand Up @@ -194,3 +196,4 @@ Initial package release.
[#96]: https://github.com/JuliaComputing/JuliaHub.jl/issues/96
[#99]: https://github.com/JuliaComputing/JuliaHub.jl/issues/99
[#100]: https://github.com/JuliaComputing/JuliaHub.jl/issues/100
[#103]: https://github.com/JuliaComputing/JuliaHub.jl/issues/103
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "JuliaHub"
uuid = "bc7fa6ce-b75e-4d60-89ad-56c957190b6e"
authors = ["JuliaHub Inc."]
version = "0.1.14"
version = "0.1.15"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Expand Down
4 changes: 3 additions & 1 deletion src/datasets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,9 @@ function _new_dataset(
end

function _open_dataset_version(auth::Authentication, name::AbstractString)::_RESTResponse
_restcall(auth, :POST, "user", "datasets", name, "versions")
r = _restcall(auth, :POST, "user", "datasets", name, "versions")
_check_internal_error(r; var="POST /user/datasets/{name}/versions")
return r
end

function _upload_dataset(upload_config, local_path; progress::Bool)
Expand Down
4 changes: 3 additions & 1 deletion src/projects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,14 @@ function _open_dataset_version(
auth::Authentication, dataset_uuid::UUID, project_uuid::UUID
)::_RESTResponse
body = Dict("project" => string(project_uuid))
return JuliaHub._restcall(
r = JuliaHub._restcall(
auth,
:POST,
("datasets", string(dataset_uuid), "versions"),
JSON.json(body),
)
_check_internal_error(r; var="POST /user/datasets/{name}/versions")
return r
end

function _close_dataset_version(
Expand Down
25 changes: 25 additions & 0 deletions src/restapi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,31 @@ function _parse_response_json(r::_RESTResponse, ::Type{T})::Tuple{T, String} whe
return _parse_response_json(r.body, T)
end

# Check that the API response is not a legacy 200 internal error, where
# we return
#
# {"success": false, "interal_error": true, "message": "..."}
#
# on internal errors. If it detects that this is an internal error, it throws
# a JuliaHubError. Returns `nothing` otherwise.
function _check_internal_error(r::_RESTResponse; var::AbstractString)
if !(r.status == 200)
return nothing
end
success = _get_json_or(r.json, "success", Any, nothing)
internal_error = _get_json_or(r.json, "internal_error", Any, nothing)
if (success === false) && (internal_error === true)
e = JuliaHubError(
"""
Internal Server Error 200 response from JuliaHub ($var):
JSON: $(sprint(show, MIME("text/plain"), r.json))
""",
)
throw(e)
end
return nothing
end

# _restcall calls _rest_request_mockable which calls _rest_request_http. The reason for this
# indirection is that the signature of _rest_request_mockable is extremely simple and therefore
# each to hook into with Mockable.
Expand Down
9 changes: 9 additions & 0 deletions test/datasets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,15 @@ end
@test_throws TypeError JuliaHub.upload_dataset(
"example-dataset-license", @__FILE__; replace=true, license=(:fulltext, 1234)
)

# Make sure we throw a JuliaHubError when we encounter an internal backend error
# that gets reported over a 200.
@test JuliaHub.upload_dataset("example-dataset-200-error-1", @__FILE__) isa JuliaHub.Dataset
MOCK_JULIAHUB_STATE[:internal_error_200] = true
@test_throws JuliaHub.JuliaHubError JuliaHub.upload_dataset(
"example-dataset-200-error", @__FILE__
)
MOCK_JULIAHUB_STATE[:internal_error_200] = false
end
empty!(MOCK_JULIAHUB_STATE)
end
11 changes: 11 additions & 0 deletions test/mocking.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ JuliaHub.__AUTH__[] = DEFAULT_GLOBAL_MOCK_AUTH
Mocking.activate()
const MOCK_JULIAHUB_STATE = Dict{Symbol, Any}()
jsonresponse(status) = d -> JuliaHub._RESTResponse(status, JSON.json(d))
function internal_error_200_response()
d = Dict(
"success" => false,
"internal_error" => true,
"message" => "Internal Server Error",
)
return JuliaHub._RESTResponse(200, JSON.json(d))
end
mocking_patch = [
Mocking.@patch(
JuliaHub._rest_request_mockable(args...; kwargs...) = _restcall_mocked(args...; kwargs...)
Expand Down Expand Up @@ -412,6 +420,9 @@ function _restcall_mocked(method, url, headers, payload; query)
Dict("repo_id" => string(UUIDs.uuid4())) |> jsonresponse(200)
end
elseif (method == :POST) && endswith(url, DATASET_VERSIONS_REGEX)
if get(MOCK_JULIAHUB_STATE, :internal_error_200, false)
return internal_error_200_response()
end
dataset, is_user = let m = match(DATASET_VERSIONS_REGEX, url)
URIs.unescapeuri(m[2]), m[1] == "user/"
end
Expand Down
6 changes: 6 additions & 0 deletions test/projects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ end
@test dataset.project.uuid === project_auth_2.project_id
@test dataset.project.is_writable === false
@test JuliaHub.upload_project_dataset(dataset_noproject, @__FILE__) isa JuliaHub.Dataset

MOCK_JULIAHUB_STATE[:internal_error_200] = true
@test_throws JuliaHub.JuliaHubError JuliaHub.upload_project_dataset(
dataset_noproject, @__FILE__
)
MOCK_JULIAHUB_STATE[:internal_error_200] = false
end
end

Expand Down
Loading