Last active
February 11, 2025 23:49
-
-
Save mtfishman/c8792a3604dc958e9cdccd65ce4f624e to your computer and use it in GitHub Desktop.
Automatically update the IntegrationTest.yml workflow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using RegistryInstances: RegistryInstances | |
function uuid_from_pkgname( | |
pkgname::String; registries=RegistryInstances.reachable_registries() | |
) | |
uuid_to_registrynames = Dict{Base.UUID,Vector{String}}() | |
for registry in registries | |
registry_uuids = RegistryInstances.uuids_from_name(registry, pkgname) | |
if !isempty(registry_uuids) | |
# There should only be one package with a given UUID in a given | |
# registry. | |
registry_uuid = only(registry_uuids) | |
if !haskey(uuid_to_registrynames, registry_uuid) | |
uuid_to_registrynames[registry_uuid] = [registry.name] | |
else | |
push!(uuid_to_registrynames[registry_uuid], registry.name) | |
end | |
end | |
end | |
if !isone(length(uuid_to_registrynames)) | |
# Multiple UUIDs exist across different registries. | |
# Prefer the version in the general registry. | |
for (uuid, registrynames) in pairs(uuid_to_registrynames) | |
if "General" ∈ registrynames | |
return uuid | |
end | |
end | |
end | |
return only(keys(uuid_to_registrynames)) | |
end | |
function registryinstance_from_pkgname( | |
pkgname::String; registries=RegistryInstances.reachable_registries() | |
) | |
# Make sure the UUID is the same across registries. | |
# If multiple registries contain the package, select | |
# the one from General. | |
uuid = uuid_from_pkgname(pkgname; registries) | |
# Find the registries that have packages with this UUID. | |
registries′ = filter(registries) do registry | |
haskey(registry, uuid) | |
end | |
# Choose the registry with the largest registered version of | |
# this package. | |
return argmax(registries′) do registry | |
# Get the maximum version number registered in this registry. | |
return maximum(keys(RegistryInstances.registry_info(registry[uuid]).version_info)) | |
end | |
end | |
function registryinstance_from_registryname( | |
registryname::String; registries=RegistryInstances.reachable_registries() | |
) | |
which_registries = findall(registries) do registry | |
return registry.name == registryname | |
end | |
return registries[only(which_registries)] | |
end | |
# Get the dependencies and weak dependencies of a package. | |
function dependencies( | |
pkgname::String; weakdeps=true, registries=RegistryInstances.reachable_registries() | |
) | |
uuid = uuid_from_pkgname(pkgname; registries) | |
registry = registryinstance_from_pkgname(pkgname; registries) | |
pkginfo = RegistryInstances.registry_info(registry[uuid]) | |
latest_version = maximum(keys(pkginfo.version_info)) | |
# Use pkginfo.compat since it generally includes Deps and WeakDeps, | |
# pkginfo.deps doesn't include WeakDeps. | |
deps = String[] | |
for (k, v) in pairs(pkginfo.compat) | |
if latest_version ∈ k | |
append!(deps, collect(keys(v))) | |
end | |
end | |
return deps | |
end | |
to_registry(registry::RegistryInstances.RegistryInstance) = registry | |
to_registry(registryname::String) = registryinstance_from_registryname(registryname) | |
function dependents( | |
pkgname::String; registries=RegistryInstances.reachable_registries(), weakdeps=true | |
) | |
registries = to_registry.(registries) | |
deps = String[] | |
for registry in registries | |
for (_, pkgentry′) in registry | |
pkgname′ = pkgentry′.name | |
if pkgname ∈ dependencies(pkgname′; weakdeps, registries) | |
push!(deps, pkgname′) | |
end | |
end | |
end | |
return deps | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[deps] | |
Git = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" | |
ITensorPkgSkeleton = "3d388ab1-018a-49f4-ae50-18094d5f71ea" | |
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" | |
RegistryInstances = "2792f1a3-b283-48e8-9a74-f99dce5104f3" | |
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include("update_integrationtest.jl") | |
pkgnames = [ | |
"BackendSelection", | |
"BlockSparseArrays", | |
"DerivableInterfaces", | |
"DiagonalArrays", | |
"GradedUnitRanges", | |
"ITensorBase", | |
"LabelledNumbers", | |
"MapBroadcast", | |
"NamedDimsArrays", | |
"NestedPermutedDimsArrays", | |
"QuantumOperatorAlgebra", | |
"QuantumOperatorDefinitions", | |
"SparseArraysBase", | |
"SymmetrySectors", | |
"TensorAlgebra", | |
"TypeParameterAccessors", | |
"UnallocatedArrays", | |
"UnspecifiedTypes", | |
] | |
update_integrationtest( | |
pkgnames; registries=["ITensorRegistry"], skip_deps=["ITensorQuantumOperatorDefinitions"] | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Git: git, readchomp | |
using ITensorPkgSkeleton: ITensorPkgSkeleton | |
using Pkg: Pkg | |
using Random: randstring | |
using RegistryInstances: RegistryInstances | |
using Suppressor: @suppress | |
include("dependents.jl") | |
function dev_dir() | |
return get(ENV, "JULIA_PKG_DEVDIR", joinpath(first(DEPOT_PATH), "dev")) | |
end | |
function downstream_workflow_path() | |
return ".github/workflows/IntegrationTest.yml" | |
end | |
function update_integrationtest(pkgnames::Vector{String}; kwargs...) | |
for pkgname in pkgnames | |
update_integrationtest(pkgname; kwargs...) | |
end | |
return nothing | |
end | |
function update_integrationtest( | |
pkgname::String; | |
registries=RegistryInstances.reachable_registries(), | |
pull_request_branch_name="update_integrationtest_$(randstring(16))", | |
pull_request_commit_message="Update IntegrationTest workflow", | |
skip_deps=String[], | |
) | |
deps = setdiff(dependents(pkgname; registries), skip_deps) | |
if isempty(deps) | |
println("Package $(pkgname).jl has no dependents, no workflow to add.\n") | |
return nothing | |
end | |
println( | |
"Attempting to update IntegrationTest.yml for package $(pkgname).jl with dependents $(deps .* ".jl").", | |
) | |
repo_url = "https://github.com/ITensor/$(pkgname).jl" | |
ghusers_and_repos = map(deps) do dep | |
uuid = uuid_from_pkgname(dep) | |
repo = RegistryInstances.registry_info(registryinstance_from_pkgname(dep)[uuid]).repo | |
return (; ghuser=split(repo, '/')[end - 1], repo=dep) | |
end | |
# Sort them so they end up sorted in the workflow. | |
sort!(ghusers_and_repos) | |
mktempdir() do tmp_path | |
current_proj = Base.active_project() | |
@suppress begin | |
Pkg.activate(tmp_path) | |
Pkg.develop(Pkg.PackageSpec(; name=pkgname)) | |
Pkg.activate(current_proj) | |
end | |
end | |
pkg_dir = joinpath(dev_dir(), pkgname) | |
cd(pkg_dir) do | |
repo_status = readchomp(`$(git()) status -s`) | |
if !isempty(repo_status) | |
println( | |
"Can't make a PR because there are uncommitted changes in the repository $pkg_dir. Commit or stash any changes before running.\n", | |
) | |
return nothing | |
end | |
@suppress begin | |
run(`$(git()) checkout main`) | |
run(`$(git()) pull`) | |
run(`$(git()) checkout -b $(pull_request_branch_name)`) | |
ITensorPkgSkeleton.generate( | |
pkgname; templates=["downstreampkgs"], downstreampkgs=ghusers_and_repos | |
) | |
end | |
repo_status = readchomp(`$(git()) status -s`) | |
if isempty(repo_status) | |
println("No changes to make to the workflow, skipping.\n") | |
return nothing | |
end | |
@suppress begin | |
run(`$(git()) add $(downstream_workflow_path())`) | |
run(`$(git()) commit -m "$(pull_request_commit_message)"`) | |
run(`$(git()) push --set-upstream origin $(pull_request_branch_name)`) | |
run(`gh repo set-default $(repo_url)`) | |
run(`gh pr create --fill`) | |
run(`$(git()) checkout main`) | |
end | |
println("*** IntegrationTest.yml updated, created pull request to $(repo_url).\n") | |
end | |
return nothing | |
end |
To run this, put all of these files into a single directory, activate and instantiate the project, and run include("run.jl")
, which will make a PR to any of the packages listed in that file if IntegrationTest.yml needs to be updated.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This workflow requires the Julia packages in the Project.toml to be installed, and also expects GitHub CLI to be installed: https://cli.github.com.