Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: fix line endings in tests on Windows #68

Merged
merged 15 commits into from
Sep 12, 2023
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,9 @@ Check [`.github/workflows/deploy.yml`](.github/workflows/deploy.yml) and [`docs/
The result of that script is available at [https://juliacomputing.github.io/MultiDocumenter.jl/](https://juliacomputing.github.io/MultiDocumenter.jl/).

You can of course also just push the output artefact directly to S3 or some other hosting service.

> **Warning**
> MultiDocumenter sites can not be deployed on Windows right now, and the `make()` function will throw an error.
> See [#70](https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70).
>
> It is still possible to develop and debug MultiDocumenter sites on Windows if the build script is run interactively (e.g. by `include`-ing it into a REPL session).
25 changes: 23 additions & 2 deletions src/MultiDocumenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,26 @@ function make(
canonical_domain::Union{AbstractString,Nothing} = nothing,
sitemap::Bool = false,
sitemap_filename::AbstractString = "sitemap.xml",
# This keyword is for internal test use only:
_override_windows_isinteractive_check::Bool = false,
)
if Sys.iswindows() && !isinteractive()
if _override_windows_isinteractive_check || isinteractive()
@warn """
Running a MultiDocumenter build interactively in Windows.
This should only be used for development and testing, as it will lead to partial
and broken builds. See https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
"""
else
msg = """
MultiDocumenter deployments are disabled on Windows due to difficulties
with handling symlinks in documentation sources.
You _can_ test this build locally by running it interactively (i.e. in the REPL).
See also: https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
"""
error(msg)
end
end
Comment on lines +143 to +162
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pfitzseb So initially I thought we could check if we run into problematic symlinks, and only then error. But I don't think that works, because by default Git on Windows will not create symlinks as far as I can tell. So the "symlinks" are just normal files, and so we can't really distinguish them easily. So instead I added the isinteractive() checks here at the very top of make.jl.

One consequence here is that we fully "break" running MultiDocumenter on Windows. So we may want to bump this to the next 0.x minor?

if isnothing(canonical_domain)
(sitemap === true) &&
throw(ArgumentError("When sitemap=true, canonical_domain must also be set"))
Expand Down Expand Up @@ -249,7 +268,8 @@ function maybe_clone(docs::Vector{MultiDocRef})
`$(git()) clone --depth 1 $(doc.giturl) --branch $(doc.branch) --single-branch --no-tags $(doc.upstream)`,
)
else
git_dir, git_worktree = abspath(joinpath(doc.upstream, ".git")), abspath(doc.upstream)
git_dir, git_worktree =
abspath(joinpath(doc.upstream, ".git")), abspath(doc.upstream)
if !isdir(git_dir)
@warn "Unable to update existing clone at $(doc.upstream): .git/ directory missing"
continue
Expand All @@ -266,7 +286,8 @@ function maybe_clone(docs::Vector{MultiDocRef})
catch e
# We're only interested in catching `git` errors here
isa(e, ProcessFailedException) || rethrow()
@error "Unable to update existing clone at $(doc.upstream)" exception = (e, catch_backtrace())
@error "Unable to update existing clone at $(doc.upstream)" exception =
(e, catch_backtrace())
Copy link
Member Author

@mortenpi mortenpi Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated formatting fixes from #61.

end
end
end
Expand Down
4 changes: 3 additions & 1 deletion src/documentertools/canonical_urls.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ function update_canonical_links(docs_directory::AbstractString; canonical::Abstr
# We'll skip all files. This includes files such as index.html, which in this
# directory will likely be the redirect. Also, links should be pointing to other
# versions, so we'll skip them too.
if !isdir(path) || islink(path)
# Note: we need to check islink() first, because on windows, calling isdir() on a
# symlink can make it throw a permissions IOError.
if islink(path) || !isdir(path)
continue
end
# Preview directory is should contain other Documenter directories, so we just add
Expand Down
6 changes: 4 additions & 2 deletions test/documentertools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import MultiDocumenter: DocumenterTools

FIXTURES = joinpath(@__DIR__, "fixtures")

normalize_newlines(s::AbstractString) = replace(s, "\r\n" => "\n")

@testset "walkdocs" begin
let fileinfos = DocumenterTools.FileInfo[]
rs = DocumenterTools.walkdocs(joinpath(FIXTURES, "pre")) do fileinfo
Expand Down Expand Up @@ -123,8 +125,8 @@ end
canonical = "https://example.org/this-is-test",
)
DocumenterTools.walkdocs(joinpath(FIXTURES, "post")) do fileinfo
post = read(fileinfo.fullpath, String)
changed = read(joinpath(out, fileinfo.relpath), String)
post = normalize_newlines(read(fileinfo.fullpath, String))
changed = normalize_newlines(read(joinpath(out, fileinfo.relpath), String))
if changed != post
@error "update_canonical_links: change and post not matching" out fileinfo
end
Expand Down
85 changes: 75 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,30 @@ docs = [
# giturl = "[email protected]:JuliaComputing/DataSets.jl.git",
),
]

# We do not support deploying docs on Windows at the moment, and MultiDocumenter
# should throw an error if it's being run on Windows (in a non-interactive session).
# See also: https://github.com/JuliaComputing/MultiDocumenter.jl/issues/70
if Sys.iswindows() && !isinteractive()
@test_throws ErrorException MultiDocumenter.make(
outpath,
docs;
search_engine = MultiDocumenter.SearchConfig(
index_versions = ["stable", "dev"],
engine = MultiDocumenter.FlexSearch,
),
custom_scripts = [
"foo/bar.js",
"https://foo.com/bar.js",
Docs.HTML("const foo = 'bar';"),
],
rootpath = rootpath,
canonical_domain = "https://example.org/",
sitemap = true,
sitemap_filename = "sitemap-mydocs.xml",
)
end

MultiDocumenter.make(
outpath,
docs;
Expand All @@ -100,15 +124,25 @@ MultiDocumenter.make(
canonical_domain = "https://example.org/",
sitemap = true,
sitemap_filename = "sitemap-mydocs.xml",
# The following keyword is not standard:
_override_windows_isinteractive_check = Sys.iswindows(),
)

@testset "MultiDocumenter.jl" begin

@testset "structure" begin
@test isdir(outpath, "inf")
@test !isdir(outpath, "inf", "previews")
@test isdir(outpath, "inf", "stable")
@test isfile(outpath, "inf", "stable", "index.html")
if Sys.iswindows()
# On Windows, symlinks are either kept as simple files, or are in fact
# symlinks, but then you would run into permission errors with isdir().
# So we need to have platform-specific test logic here.
path = joinpath(outpath, "inf", "stable")
@test islink(path) || isfile(path)
else
@test isdir(outpath, "inf", "stable")
@test isfile(outpath, "inf", "stable", "index.html")
end

@test read(joinpath(outpath, "inf", "index.html"), String) == """
<!--This file is automatically generated by Documenter.jl-->
Expand All @@ -122,8 +156,7 @@ MultiDocumenter.make(


@testset "custom scripts" begin
index = read(joinpath(outpath, "inf", "stable", "index.html"), String)

index = read(joinpath(outpath, "inf", "v1.6.4", "index.html"), String)
@test occursin(
"""<script charset="utf-8" type="text/javascript">window.MULTIDOCUMENTER_ROOT_PATH = '$rootpath'</script>""",
index,
Expand All @@ -140,12 +173,36 @@ MultiDocumenter.make(
"""<script charset="utf-8" type="text/javascript">const foo = 'bar';</script>""",
index,
)

if !Sys.iswindows()
# Going through symlinks does not work on Windows
index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
@test occursin(
"""<script charset="utf-8" type="text/javascript">window.MULTIDOCUMENTER_ROOT_PATH = '$rootpath'</script>""",
index,
)
@test occursin(
"""<script charset="utf-8" src="../../foo/bar.js" type="text/javascript"></script>""",
index,
)
@test occursin(
"""<script charset="utf-8" src="https://foo.com/bar.js" type="text/javascript"></script>""",
index,
)
@test occursin(
"""<script charset="utf-8" type="text/javascript">const foo = 'bar';</script>""",
index,
)
end
end

@testset "canonical URLs" begin
index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
canonical_href = "<link href=\"https://example.org/MultiDocumenter.jl/inf/stable/\" rel=\"canonical\"/>"
@test occursin(canonical_href, index)
# We can't traverse symlinks on Windows, so we ignore this case
if !Sys.iswindows()
index = read(joinpath(outpath, "inf", "stable", "index.html"), String)
canonical_href = "<link href=\"https://example.org/MultiDocumenter.jl/inf/stable/\" rel=\"canonical\"/>"
@test occursin(canonical_href, index)
end

index = read(joinpath(outpath, "inf", "v1.6.0", "index.html"), String)
canonical_href = "<link href=\"https://example.org/MultiDocumenter.jl/inf/stable/\" rel=\"canonical\"/>"
Expand All @@ -158,9 +215,17 @@ MultiDocumenter.make(
@test !isempty(store_content)
@test occursin("Infiltrator.jl", store_content)
@test occursin("@infiltrate", store_content)
@test occursin("$(rootpath)inf/stable/", store_content)
@test occursin("$(rootpath)inf/stable/", store_content)
@test !occursin("/inf/dev/", store_content)
# We can't traverse symlinks on Windows, so stable/ things do not get
# written into the search index. Instead, it looks like we write dev/
if Sys.iswindows()
@test !occursin("$(rootpath)inf/stable/", store_content)
@test !occursin("$(rootpath)inf/stable/", store_content)
@test occursin("/inf/dev/", store_content)
else
@test occursin("$(rootpath)inf/stable/", store_content)
@test occursin("$(rootpath)inf/stable/", store_content)
@test !occursin("/inf/dev/", store_content)
end
end

@testset "sitemap" begin
Expand Down
Loading