Skip to content
Closed
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
20 changes: 20 additions & 0 deletions .github/workflows/sublibrary-downgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ jobs:
[ -n "${{ inputs.skip }}" ] && effective="$effective,${{ inputs.skip }}"
echo "Effective downgrade skip: $effective"
echo "EFFECTIVE_SKIP=$effective" >> "$GITHUB_ENV"
- name: "Save project metadata for QA"
if: "${{ inputs.group-env-value == 'QA' }}"
shell: bash
run: |
save_dir="$RUNNER_TEMP/sciml-downgrade-original-project"
mkdir -p "$save_dir"
cp "${{ matrix.project }}/Project.toml" "$save_dir/Project.toml"
- uses: julia-actions/julia-downgrade-compat@v2
with:
projects: ${{ matrix.project }}
Expand All @@ -180,6 +187,19 @@ jobs:
- uses: julia-actions/julia-buildpkg@v1
with:
project: ${{ matrix.project }}
- name: "Checkout SciML/.github for the downgrade metadata helper"
if: "${{ inputs.group-env-value == 'QA' }}"
uses: actions/checkout@v7
with:
repository: SciML/.github
path: .sciml-dotgithub
- name: "Restore project metadata before QA"
if: "${{ inputs.group-env-value == 'QA' }}"
shell: bash
run: |
save_dir="$RUNNER_TEMP/sciml-downgrade-original-project"
cp "$save_dir/Project.toml" "${{ matrix.project }}/Project.toml"
julia --startup-file=no .sciml-dotgithub/scripts/restore_downgraded_project.jl "${{ matrix.project }}"
- uses: julia-actions/julia-runtest@v1
with:
project: ${{ matrix.project }}
Expand Down
69 changes: 69 additions & 0 deletions scripts/restore_downgraded_project.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env julia

using TOML

function restored_manifest_entry(project::AbstractDict, path::AbstractString)
entry = Dict{String, Any}(
"path" => path,
"uuid" => project["uuid"],
)
hard_deps = sort!(collect(keys(get(project, "deps", Dict{String, Any}()))))
isempty(hard_deps) || (entry["deps"] = hard_deps)
for key in ("weakdeps", "extensions")
values = get(project, key, nothing)
values isa AbstractDict && !isempty(values) && (entry[key] = deepcopy(values))
end
haskey(project, "version") && (entry["version"] = project["version"])
return entry
end

function local_manifest_entry(entries, manifest_dir::AbstractString, project_dir::AbstractString)
matches = findall(entries) do entry
path = get(entry, "path", nothing)
path isa AbstractString || return false
return realpath(abspath(manifest_dir, path)) == realpath(project_dir)
end
length(matches) == 1 || error(
"expected exactly one local manifest entry for $project_dir, found $(length(matches))",
)
return only(matches)
end

"""
restore_downgraded_project(project_dir)

Repair the local package entry in a downgrade-generated `Manifest.toml` after
restoring the package's original `Project.toml`. Resolved package versions and
test-only manifest entries are retained.
"""
function restore_downgraded_project(project_dir::AbstractString)
project_dir = normpath(abspath(project_dir))
project_path = joinpath(project_dir, "Project.toml")
manifest_path = joinpath(project_dir, "Manifest.toml")
project = TOML.parsefile(project_path)
manifest = TOML.parsefile(manifest_path)

package_name = project["name"]
entries = manifest["deps"][package_name]
entry_index = local_manifest_entry(entries, dirname(manifest_path), project_dir)
existing_path = entries[entry_index]["path"]
entries[entry_index] = restored_manifest_entry(project, existing_path)
pop!(manifest, "project_hash", nothing)

temporary_path, io = mktemp(dirname(manifest_path))
try
TOML.print(io, manifest; sorted = true)
close(io)
mv(temporary_path, manifest_path; force = true)
catch
close(io)
rm(temporary_path; force = true)
rethrow()
end
return nothing
end

if abspath(PROGRAM_FILE) == @__FILE__
length(ARGS) == 1 || error("usage: restore_downgraded_project.jl PROJECT_DIR")
restore_downgraded_project(only(ARGS))
end
64 changes: 64 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,70 @@ include(SCRIPT)
const DEVELOP_SCRIPT = joinpath(@__DIR__, "..", "scripts", "develop_sources.jl")
include(DEVELOP_SCRIPT)

const RESTORE_DOWNGRADE_SCRIPT =
joinpath(@__DIR__, "..", "scripts", "restore_downgraded_project.jl")
include(RESTORE_DOWNGRADE_SCRIPT)

@testset "restore downgraded project manifest metadata" begin
root = mktempdir()
write(
joinpath(root, "Project.toml"), """
name = "Root"
uuid = "00000000-0000-0000-0000-000000000001"
version = "1.2.3"

[deps]
Runtime = "00000000-0000-0000-0000-000000000002"

[weakdeps]
Weak = "00000000-0000-0000-0000-000000000003"

[extensions]
RootWeakExt = "Weak"
""",
)
write(
joinpath(root, "Manifest.toml"), """
julia_version = "1.10.0"
manifest_format = "2.0"
project_hash = "stale"

[[deps.Root]]
deps = ["Runtime", "TestOnly"]
path = "."
uuid = "00000000-0000-0000-0000-000000000001"
version = "1.2.3"

[[deps.Runtime]]
git-tree-sha1 = "runtime-tree"
uuid = "00000000-0000-0000-0000-000000000002"
version = "2.0.0"

[[deps.TestOnly]]
git-tree-sha1 = "test-tree"
uuid = "00000000-0000-0000-0000-000000000004"
version = "3.0.0"
""",
)

before = TOML.parsefile(joinpath(root, "Manifest.toml"))
restore_downgraded_project(root)
after = TOML.parsefile(joinpath(root, "Manifest.toml"))

@test !haskey(after, "project_hash")
@test after["deps"]["Runtime"] == before["deps"]["Runtime"]
@test after["deps"]["TestOnly"] == before["deps"]["TestOnly"]
root_entry = only(after["deps"]["Root"])
@test root_entry["path"] == "."
@test root_entry["uuid"] == "00000000-0000-0000-0000-000000000001"
@test root_entry["version"] == "1.2.3"
@test root_entry["deps"] == ["Runtime"]
@test root_entry["weakdeps"] == Dict(
"Weak" => "00000000-0000-0000-0000-000000000003",
)
@test root_entry["extensions"] == Dict("RootWeakExt" => "Weak")
end

# Build a fixture monorepo `lib/` tree in a temp dir.
# A (base, no internal deps)
# B deps A
Expand Down
Loading