Skip to content

Commit

Permalink
Merge pull request #62 from JuliaDocs/mg/58-linkcheck
Browse files Browse the repository at this point in the history
Check links inside the bibliography
  • Loading branch information
goerz authored Nov 29, 2023
2 parents dafeccf + 602ca52 commit c99bee1
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 3 deletions.
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Warn about markdown link syntax in `.bib` files [[#60][]]
* Warn about invalid DOIs in `.bib` files. The DOI field should never contain a URL (`https://doi.org/...`). This is detected as a special case, and the DOI is extracted from the URL.
* Automatically link both URL and DOI fields. This fixes a regression in `v1.3.0`, which would throw an error for `@book` and `@proceeding` entries with both a URL and a DOI field. Now, the DOI in such a case will be automatically linked via the `Title` field, and the DOI via the `organization`/`publisher`/`address` fields, similar to the behavior in `v1.2.0`. You may prefer to have the DOI linked via that `Title`, in which case you should add a `Note` field containing the `URL` (using `\url`/`\href`, as appropriate).

* Calling `makedocs` with `linkcheck=true` now also checks links (e.g., DOIs) inside the bibliography. [[#58][]]


## [Version 1.3.1][1.3.1] - 2023-11-02

Expand Down Expand Up @@ -151,6 +152,7 @@ There were several bugs and limitations in version `1.2.x` for which some existi
[#61]: https://github.com/JuliaDocs/DocumenterCitations.jl/pull/61
[#60]: https://github.com/JuliaDocs/DocumenterCitations.jl/issues/60
[#59]: https://github.com/JuliaDocs/DocumenterCitations.jl/issues/59
[#58]: https://github.com/JuliaDocs/DocumenterCitations.jl/issues/58
[#56]: https://github.com/JuliaDocs/DocumenterCitations.jl/pull/56
[#53]: https://github.com/JuliaDocs/DocumenterCitations.jl/issues/53
[#42]: https://github.com/JuliaDocs/DocumenterCitations.jl/pull/42
Expand Down
2 changes: 1 addition & 1 deletion docs/src/refs.bib
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ @mastersthesis{GoerzDiploma2010
Title = {Optimization of a Controlled Phasegate for Ultracold Calcium Atoms in an Optical Lattice},
School = {Freie Universität Berlin},
type = {{Diplomarbeit}},
url = {http://michaelgoerz.net/research/diploma_thesis.pdf},
url = {https://michaelgoerz.net/research/diploma_thesis.pdf},
Year = {2010},
}

Expand Down
2 changes: 1 addition & 1 deletion src/DocumenterCitations.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module DocumenterCitations

using Documenter
using Documenter: Documenter, DOCUMENTER_VERSION
using Documenter.Builder
using Documenter.Selectors
using Documenter.Expanders
Expand Down
14 changes: 14 additions & 0 deletions src/bibliography_node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,17 @@ function Documenter.LaTeXWriter.latex(
println(io, "}% end @bibliography")

end


function Documenter.linkcheck(
node::MarkdownAST.Node,
bibliography::BibliographyNode,
doc::Documenter.Document
)
success = true
for item in bibliography.items
success &= !(Documenter.linkcheck(item.reference, doc) === false)
# `linkcheck` may return `true` / `false` / `nothing`
end
return success
end
3 changes: 3 additions & 0 deletions src/expand_bibliography.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Selectors.order(::Type{ExpandBibliography}) = 2.12 # after CollectCitations
function Selectors.runner(::Type{ExpandBibliography}, doc::Documenter.Document)
Documenter.is_doctest_only(doc, "ExpandBibliography") && return
@info "ExpandBibliography: expanding `@bibliography` blocks."
if (DOCUMENTER_VERSION < v"1.2") && doc.user.linkcheck
@warn "Checking links in the bibliography (`linkcheck=true`) requires Documenter >= 1.2" DOCUMENTER_VERSION
end
expand_bibliography(doc)
end

Expand Down
15 changes: 15 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ using DocumenterCitations
include("test_undefined_citations.jl")
end

println("\n* test link checking (test_linkcheck.jl):")
@time @safetestset "linkcheck" begin
import Pkg
using Documenter: DOCUMENTER_VERSION
run_linkcheck = true
if !Sys.isexecutable("/usr/bin/env") # used by mock `curl`
run_linkcheck = false
@info "Skipped test_linkcheck.jl (cannot mock `curl`)"
elseif DOCUMENTER_VERSION < v"1.2"
run_linkcheck = false
@info "Skipped test_linkcheck.jl (old version of Documenter)"
end
run_linkcheck && include("test_linkcheck.jl")
end

print("\n")

end
Expand Down
45 changes: 45 additions & 0 deletions test/test_linkcheck.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using DocumenterCitations
using Test
using IOCapture: IOCapture

include("run_makedocs.jl")


@testset "Check invalid url in .bib file " begin

# https://github.com/JuliaDocs/DocumenterCitations.jl/issues/58

root = splitext(@__FILE__)[1]

bib = CitationBibliography(joinpath(root, "src", "invalidlink.bib"), style=:numeric)

run_makedocs(
root;
linkcheck=true,
sitename="Test",
plugins=[bib],
pages=["Home" => "index.md", "References" => "references.md",],
check_failure=true,
env=Dict("PATH" => "$root:$(ENV["PATH"])"), # Unix only
# The updated PATH allows to use the mock `curl` in `root`.
) do dir, result, success, backtrace, output

@test !success
@test contains(output, r"Error:.*http://www.invalid-server.doesnotexist/page.html")
@test contains(
output,
"Error: linkcheck 'http://httpbin.org/status/404' status: 404."
)
@test contains(
output,
"Error: linkcheck 'http://httpbin.org/status/500' status: 500."
)
@test contains(
output,
"Error: linkcheck 'http://httpbin.org/status/403' status: 403."
)
@test contains(result.msg, "`makedocs` encountered an error [:linkcheck]")

end

end
26 changes: 26 additions & 0 deletions test/test_linkcheck/curl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env julia

RESPONSE = Dict(
"http://httpbin.org/status/404" => "404 http://httpbin.org/status/404 ",
"http://httpbin.org/status/500" => "500 http://httpbin.org/status/500 ",
"http://httpbin.org/status/403" => "403 http://httpbin.org/status/403 ",
)

# The above responses must match what `curl` as called by the `linkcheck`
# function in Documenter would return. In particular, `linkcheck` calls `curl`
# with `--write-out "%{http_code} %{url_effective} %{redirect_url}"`

if "--version" in ARGS
println("mocked")
exit(0)
else
url = ARGS[findfirst(startswith("http"), ARGS)]
try
print(RESPONSE[url])
catch
# URLs not in RESPONSE will cause an failure, equivalent to the normal
# `curl` not being able to connect.
exit(1)
end
exit(0)
end
8 changes: 8 additions & 0 deletions test/test_linkcheck/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Testing link checks for broken links


## Problem description

The `linkcheck` option for `makedocs` should complain about [broken links](http://httpbin.org/status/403).

Ref [GoerzPhd2015](@cite) contains broken links.
8 changes: 8 additions & 0 deletions test/test_linkcheck/src/invalidlink.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@phdthesis{GoerzPhd2015,
Author = {Goerz, Michael},
Title = {Optimizing Robust Quantum Gates in Open Quantum Systems},
School = {Universität Kassel},
url = {http://www.invalid-server.doesnotexist/page.html},
Year = {2015},
note = {See \url{http://httpbin.org/status/404} for additional formats. Source available on \href{http://httpbin.org/status/500}{Github}},
}
4 changes: 4 additions & 0 deletions test/test_linkcheck/src/references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## References

```@bibliography
```

0 comments on commit c99bee1

Please sign in to comment.