diff --git a/Artifacts.toml b/Artifacts.toml new file mode 100644 index 0000000..f4f9157 --- /dev/null +++ b/Artifacts.toml @@ -0,0 +1,6 @@ +[hello_world] +git-tree-sha1 = "538e83d637ab07ada6d841aa2454e0d5af4e52b3" + + [[hello_world.download]] + sha256 = "d81c7e810cd9d3588a7aa0aaffb9fbc8c4db6ad2bc27f8ddb8f5382b44a5a4f9" + url = "https://github.com/pat-alt/ArtifactUtils.jl/releases/download/artifacts-latest/538e83d637ab07ada6d841aa2454e0d5af4e52b3.tar.gz" diff --git a/Project.toml b/Project.toml index 543e20a..3dd626b 100644 --- a/Project.toml +++ b/Project.toml @@ -12,6 +12,7 @@ ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c" SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" gh_cli_jll = "5d31d589-30fb-542f-b82d-10325e863e38" +ghr_jll = "07c12ed4-43bc-5495-8a2a-d5838ef8d533" [compat] Git = "1" diff --git a/README.md b/README.md index 747c59d..4978e79 100644 --- a/README.md +++ b/README.md @@ -97,3 +97,34 @@ file. You can also call `add_artifact!` with the `gist` result object. ```julia julia> add_artifact!("Artifacts.toml", "hello_world", gist) ``` + +### Archive a directory and upload it as release + +You can also create an artifact from a directory using `artifact_from_directory` and +then upload it as a tagged release with `upload_to_release`. Note that `upload_to_release` +requires login using your `GITHUB_TOKEN`, which needs to be available from the environment. + +```julia +julia> using ArtifactUtils + +julia> tempdir = mktempdir(); + +julia> write(joinpath(tempdir, "file"), "hello"); + +julia> artifact_id = artifact_from_directory(tempdir) +SHA1("538e83d637ab07ada6d841aa2454e0d5af4e52b3") + +julia> release = upload_to_release(artifact_id) +@Info (ArtifactUtils#release_from_file#46): Uploading tarballs to pat-alt/ArtifactUtils.jl tag `artifacts-latest` + │ + ╰──────────────────────────────────────────────── + Sun, 14 Jan 2024 17:05:02 +--> Uploading: 538e83d637ab07ada6d841aa2454e0d5af4e52b3.tar.gz +ArtifactUtils.ReleaseUploadResult(SHA1("538e83d637ab07ada6d841aa2454e0d5af4e52b3"), "538e83d637ab07ada6d841aa2454e0d5af4e52b3.tar.gz", "/var/folders/ct/w1pc0ggd44907l8fkl8m5pdslbh6sh/T/jl_I38b3Z/538e83d637ab07ada6d841aa2454e0d5af4e52b3.tar.gz", "https://github.com/pat-alt/ArtifactUtils.jl/releases/download/artifacts-latest/538e83d637ab07ada6d841aa2454e0d5af4e52b3.tar.gz", "d81c7e810cd9d3588a7aa0aaffb9fbc8c4db6ad2bc27f8ddb8f5382b44a5a4f9", "artifacts-latest") +``` + +Simply call the `add_artifact!` with the `release` result object. + +```julia +julia> add_artifact!("Artifacts.toml", "hello_world", release) +``` diff --git a/src/ArtifactUtils.jl b/src/ArtifactUtils.jl index f27a9ea..906514b 100644 --- a/src/ArtifactUtils.jl +++ b/src/ArtifactUtils.jl @@ -12,7 +12,8 @@ using Base: SHA1 using SHA using Downloads: download -export add_artifact!, artifact_from_directory, upload_to_gist, upload_all_to_gist! +export add_artifact!, artifact_from_directory +export upload_to_gist, upload_all_to_gist!, upload_to_release include("utils.jl") include("gistutils.jl") @@ -298,6 +299,8 @@ function print_artifact_entry( TOML.print(io, dict; sorted = true) end +include("upload_to_release.jl") + function Base.show(io::IO, ::MIME"text/plain", gist::GistUploadResult) print(io, upload_to_gist, "(") show(io, gist.artifact_id) diff --git a/src/release_utils.jl b/src/release_utils.jl new file mode 100644 index 0000000..d374013 --- /dev/null +++ b/src/release_utils.jl @@ -0,0 +1,28 @@ +function release_from_file(filepath::AbstractString; tag::AbstractString) + + @assert isfile(filepath) + + # Get the repo name from the git remote url + if !haskey(ENV, "GITHUB_TOKEN") + @warn "For automatic github deployment, need GITHUB_TOKEN. Not found in ENV, attemptimg global git config." + end + + origin_url = strip(chomp(read(`git config --get remote.origin.url`, String))) + deploy_repo = "$(basename(dirname(origin_url)))/$(basename(origin_url))" + deploy_repo = replace(deploy_repo, ".git" => "") + + # Upload tarballs to a special github release + @info("Uploading tarballs to $(deploy_repo) tag `$(tag)`") + + ghr() do ghr_exe + println( + readchomp( + `$ghr_exe -replace -u $(dirname(deploy_repo)) -r $(basename(deploy_repo)) $(tag) $(filepath)`, + ), + ) + end + + tarball_url = "https://github.com/$(deploy_repo)/releases/download/$(tag)/$(basename(filepath))" + + return tarball_url +end \ No newline at end of file diff --git a/src/upload_to_release.jl b/src/upload_to_release.jl new file mode 100644 index 0000000..1a99de2 --- /dev/null +++ b/src/upload_to_release.jl @@ -0,0 +1,117 @@ +using ghr_jll + +struct ReleaseUploadResult + artifact_id::SHA1 + filename::String + localpath::Union{String,Nothing} + url::String + sha256::String + tag::String +end + +include("release_utils.jl") + +""" + upload_to_release( + artifact_id::SHA1, + [tarball]; + tag::AbstractString="artifacts-latest", + honor_overrides = false, + # Following options are aviailable only when `tarball` is not specified: + name::AbstractString = "\$artifact_id.tar.gz", + extension::AbstractString = ".tar.gz", + ) -> release + +Create an artifact archive at path `tarball` (or in a temporary location) and upload it to +release. The returned value `release` can be passed to `add_artifact!`. + +# Extended help + +## Examples +```julia +using ArtifactUtils +add_artifact!("Artifact.toml", "name", upload_to_release(artifact_from_directory("source"))) +``` + +creates an artifact from files in the `"source"` directory, uploads it to a release, and then +adds it to `"Artifact.toml"` with the name `"name"`. + +## Keyword Arguments +- `tag`: the tag of the release to upload to +- `name`: name of the archive file, including file extension +- `extension`: file extension of the tarball. It can be used for specifying the compression + method. +- `honor_overrides`: see `Pkg.Artifacts.archive_artifact` +""" +function upload_to_release end + +function upload_to_release( + artifact_id::SHA1, + tarball::AbstractString; + tag::AbstractString="artifacts-latest", + archive_options..., +) + mkpath(dirname(tarball)) + archive_artifact(artifact_id, tarball; archive_options...) + sha256 = sha256sum(tarball) + url = release_from_file(tarball; tag=tag) + return ReleaseUploadResult( + artifact_id, + basename(tarball), + abspath(tarball), + url, + sha256, + tag, + ) +end + +function upload_to_release( + artifact_id::SHA1; + name::Union{AbstractString,Nothing}=nothing, + extension::Union{AbstractString,Nothing}=nothing, + options..., +) + if name !== nothing && extension !== nothing + error( + "Options `name` and `extension` are mutually exclusive. Got: name = ", + name, + " extension = ", + extension, + ) + end + + tarball = if name === nothing + string(artifact_id, something(extension, ".tar.gz")) + else + name + end + + return mktempdir() do dir + upload_to_release(artifact_id, joinpath(dir, tarball); options...) + end +end + +""" + add_artifact!( + artifacts_toml::String, + name::String, + release::ReleaseUploadResult; + options..., + ) + +Extends the `add_artifact!` function to `ReleaseUploadResult`. +""" +function add_artifact!( + artifacts_toml::String, + name::String, + release::ReleaseUploadResult; + options..., +) + bind_artifact!( + artifacts_toml, + name, + release.artifact_id; + download_info=[(release.url, release.sha256)], + options..., + ) +end \ No newline at end of file