diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b8b603f4..16ab6a1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +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] + +### Added + +* Support for displaying and submitting batch image options with tags when working with JuliaHub instances v6.10 and above. ([#94]) + ## Version [v0.1.13] - 2025-04-28 ### Fixed diff --git a/src/batchimages.jl b/src/batchimages.jl index b3384ddd8..8fedfff31 100644 --- a/src/batchimages.jl +++ b/src/batchimages.jl @@ -17,6 +17,8 @@ Base.@kwdef struct BatchImage image::String _cpu_image_key::Union{String, Nothing} _gpu_image_key::Union{String, Nothing} + _image_tag::Union{String, Nothing} + _image_sha::Union{String, Nothing} _is_product_default::Bool _interactive_product_name::Union{String, Nothing} end @@ -34,6 +36,8 @@ function Base.show(io::IO, ::MIME"text/plain", image::BatchImage) print(io, '\n', " image: ", image.image) isnothing(image._cpu_image_key) || print(io, "\n CPU image: ", image._cpu_image_key) isnothing(image._gpu_image_key) || print(io, "\n GPU image: ", image._gpu_image_key) + isnothing(image._image_tag) || print(io, ":$(image._image_tag)") + isnothing(image._image_sha) || print(io, ":$(image._image_sha)") if !isnothing(image._interactive_product_name) print(io, "\n Features:") print(io, "\n - Expose Port: ✓") @@ -186,7 +190,7 @@ function _batchimages_legacy(auth::Authentication) end function _api_product_image_groups(auth::Authentication) - r = _restcall(auth, :GET, "juliaruncloud", "product_image_groups") + r = _restcall(auth, :GET, "juliaruncloud", "product_image_groups"; query=[("extended", "true")]) r.status == 200 || _throw_invalidresponse(r) return _parse_response_json(r, Dict) end @@ -214,6 +218,8 @@ Base.@kwdef mutable struct _ImageKeys isdefault::Bool = false cpu::Union{String, Nothing} = nothing gpu::Union{String, Nothing} = nothing + tag::Union{String, Nothing} = nothing + sha::Union{String, Nothing} = nothing end function _group_images(images; image_group::AbstractString) @@ -231,9 +237,13 @@ function _group_images(images; image_group::AbstractString) end image_key_name = _get_json(image, "image_key_name", String) display_name = _get_json(image, "display_name", String) + tag = _get_json_or(image, "image_tag", Union{String, Nothing}) + sha = _get_json_or(image, "image_sha", Union{String, Nothing}) image_type = _parse_image_group_entry_type(image) isnothing(image_type) && continue # invalid image type will return a nothing, which we will ignore - imagekeys = get!(grouped_images, display_name, _ImageKeys(; isdefault=image_type.isdefault)) + imagekeys = get!( + grouped_images, display_name, _ImageKeys(; isdefault=image_type.isdefault, tag, sha) + ) # If this image key set is already problematic, no point in checking further imagekeys.error && continue # We make sure that there are no conflicts with base- and option- image types @@ -333,6 +343,8 @@ function _batchimages_62(auth::Authentication) _gpu_image_key = imagekey.gpu, _is_product_default = imagekey.isdefault, _interactive_product_name = interactive_product_name, + _image_tag = imagekey.tag, + _image_sha = imagekey.sha, ) end end diff --git a/src/jobsubmission.jl b/src/jobsubmission.jl index d22e05d49..fa23a360e 100644 --- a/src/jobsubmission.jl +++ b/src/jobsubmission.jl @@ -22,6 +22,7 @@ struct _JobSubmission1 # Job image configuration product_name::Union{String, Nothing} image::Union{String, Nothing} + image_tag::Union{String, Nothing} image_sha256::Union{String, Nothing} sysimage_build::Union{String, Nothing} sysimage_manifest_sha::Union{String, Nothing} @@ -56,6 +57,7 @@ struct _JobSubmission1 # Job image configuration product_name::Union{AbstractString, Nothing}=nothing, image::Union{AbstractString, Nothing}=nothing, + image_tag::Union{AbstractString, Nothing}=nothing, image_sha256::Union{AbstractString, Nothing}=nothing, sysimage_build::Union{Bool, Nothing}=nothing, sysimage_manifest_sha::Union{AbstractString, Nothing}=nothing, @@ -138,7 +140,8 @@ struct _JobSubmission1 appbundle, appbundle_upload_info, registry_name, package_name, branch_name, git_revision, # Job image configuration - product_name, image, image_sha256, string(sysimage_build), sysimage_manifest_sha, + product_name, image, image_tag, image_sha256, + string(sysimage_build), sysimage_manifest_sha, # Compute configuration node_class, string(cpu), string(nworkers), _string_or_nothing(elastic), _string_or_nothing(min_workers_required), @@ -1311,7 +1314,12 @@ function _job_submit_args( end batch.image._cpu_image_key end - (; product_name=batch.image.product, image) + (; + product_name=batch.image.product, + image, + image_tag=batch.image._image_tag, + image_sha256=batch.image._image_sha, + ) else (;) end diff --git a/test/mocking.jl b/test/mocking.jl index be75961e5..6a7a54ebf 100644 --- a/test/mocking.jl +++ b/test/mocking.jl @@ -468,7 +468,7 @@ function _restcall_mocked(method, url, headers, payload; query) else serve_kafka(logengine, method, Dict(query)) end - elseif (method == :GET) && endswith(url, "/juliaruncloud/product_image_groups") + elseif (method == :GET) && occursin("/juliaruncloud/product_image_groups", url) Dict( "image_groups" => Dict( "base_and_opt" => [