diff --git a/Project.toml b/Project.toml index 2a6a806..ae29cdc 100644 --- a/Project.toml +++ b/Project.toml @@ -7,14 +7,12 @@ AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" MarkdownAST = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" -OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" [compat] AbstractTrees = "0.4.5" CommonMark = "0.8.15" Dates = "1" MarkdownAST = "0.1.2" -OrderedCollections = "1.7.0" julia = "1.6" [extras] diff --git a/README.md b/README.md index e7f0560..d22e5f3 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,9 @@ The typical workflow is as follows: ### Parsing changelogs Changelog also provides functionality for parsing changelogs into a simple structure which can be programmatically queried, -e.g. to check what the changes are for a particular version. The API for this functionality consists of: +e.g. to check what the changes are for a particular version. This functionality is primarily intended for parsing [KeepAChangeLog](https://keepachangelog.com/en/1.1.0/)-style changelogs, that have a title as a H1 (e.g. `#`) markdown header, followed by a list of versions with H2-level headers (`##`) formatted like `[1.1.0] - 2019-02-15` with or without a link on the version number, followed by a bulleted list of changes, potentially in subsections, each with H3 header. For such changelogs, parsing should be stable. We may also attempt to parse a wider variety of headers, for which the extent that we can parse may change in non-breaking releases (typically improving the parsing, but potentially regressing in some cases). + +The API for this functionality consists of: - `SimpleChangelog`: structure that contains a simple representation of a changelog. - `VersionInfo`: structure that contains a simple representation of a version in a changelog. @@ -84,10 +86,10 @@ SimpleChangelog with - First release. See README.md for currently supported functionality. ``` -The changes for 1.1.0 can be obtained by `log.versions[1].sectioned_changes`: +The changes for 1.1.0 can be obtained by `changelog.versions[1].sectioned_changes`: ```julia julia> changelog.versions[1].sectioned_changes -OrderedCollections.OrderedDict{String, Vector{String}} with 1 entry: - "Added" => ["Links of the form `[]`, where `` is a commit hashof length 7 or 40, are now linkified. (#4)"] +1-element Vector{Pair{String, Vector{String}}}: + "Added" => ["Links of the form `[]`, where `` is a commit hashof length 7 or 40, are now linkified. (#4)"] ``` diff --git a/src/Changelog.jl b/src/Changelog.jl index 60f8089..04da3b0 100644 --- a/src/Changelog.jl +++ b/src/Changelog.jl @@ -10,7 +10,6 @@ module Changelog using MarkdownAST using Dates using AbstractTrees -using OrderedCollections: OrderedDict import CommonMark as CM VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("public parsefile, VersionInfo, SimpleChangelog, generate, tryparsefile")) diff --git a/src/SimpleChangelog.jl b/src/SimpleChangelog.jl index 8d08b43..42762c9 100644 --- a/src/SimpleChangelog.jl +++ b/src/SimpleChangelog.jl @@ -7,7 +7,7 @@ A struct representing the information in a changelog about a particular version, - `url::Union{Nothing, String}`: a URL associated to the version, if available - `date::Union{Nothing, Date}`: a date associated to the version, if available - `toplevel_changes::Vector{String}`: a list of changes which are not within a section -- `sectioned_changes::OrderedDict{String, Vector{String}}`: an ordered mapping of section name to a list of changes in that section. +- `sectioned_changes::Vector{Pair{String, Vector{String}}}`: an ordered mapping of section name to a list of changes in that section. """ struct VersionInfo @@ -15,7 +15,7 @@ struct VersionInfo url::Union{Nothing, String} date::Union{Nothing, Date} toplevel_changes::Vector{String} - sectioned_changes::OrderedDict{String, Vector{String}} + sectioned_changes::Vector{Pair{String, Vector{String}}} end function Base.show(io::IO, ::MIME"text/plain", v::VersionInfo) return full_show(io, v) @@ -45,7 +45,7 @@ function full_show(io, v::VersionInfo; indent = 0, showtype = true) end if !isempty(v.sectioned_changes) - for (section_name, bullets) in pairs(v.sectioned_changes) + for (section_name, bullets) in v.sectioned_changes print(io, "\n", pad, " - $section_name") for b in bullets print(io, "\n", pad, " - $b") @@ -101,6 +101,9 @@ end parse(::Type{SimpleChangelog}, text::AbstractString) Parse a [`SimpleChangelog`](@ref) from a markdown-formatted string. + +!!! note + This functionality is primarily intended for parsing [KeepAChangeLog](https://keepachangelog.com/en/1.1.0/)-style changelogs, that have a title as a H1 (e.g. `#`) markdown header, followed by a list of versions with H2-level headers (`##`) formatted like `[1.1.0] - 2019-02-15` with or without a link on the version number, followed by a bulleted list of changes, potentially in subsections, each with H3 header. For such changelogs, parsing should be stable. We may also attempt to parse a wider variety of headers, for which the extent that we can parse may change in non-breaking releases (typically improving the parsing, but potentially regressing in some cases). """ function Base.parse(::Type{SimpleChangelog}, text::AbstractString) # parse into CommonMark AST diff --git a/src/parse_changelog.jl b/src/parse_changelog.jl index 29842f3..1008ec8 100644 --- a/src/parse_changelog.jl +++ b/src/parse_changelog.jl @@ -181,7 +181,7 @@ function _parse_simple_changelog!(ast::MarkdownAST.Node) # Now let us formulate the changelog for this version # We may have subsections or just a flat list of changes - sectioned_changes = OrderedDict{String, Vector{String}}() + sectioned_changes = Pair{String, Vector{String}}[] seen = Set() for subsection in filter_children(version_section, MarkdownAST.Heading) subsection_name = text_content(subsection.heading_node) @@ -190,7 +190,7 @@ function _parse_simple_changelog!(ast::MarkdownAST.Node) # and if we hit a text, we know it's not contained in an item that we are also pulling out. items = filter_tree(subsection, Union{MarkdownAST.Item, MarkdownAST.Text}) union!(seen, items) - sectioned_changes[subsection_name] = bullets_to_list(items) + push!(sectioned_changes, subsection_name => bullets_to_list(items)) end # see if there were items not within a subsection other_items = setdiff(filter_tree(version_section, Union{MarkdownAST.Item, MarkdownAST.Text}), seen) diff --git a/test/SimpleChangelog.jl b/test/SimpleChangelog.jl index cf4cf94..111a980 100644 --- a/test/SimpleChangelog.jl +++ b/test/SimpleChangelog.jl @@ -1,6 +1,6 @@ -using Changelog: VersionInfo, SimpleChangelog, OrderedDict, tryparsefile +using Changelog: VersionInfo, SimpleChangelog, tryparsefile @testset "VersionInfo and SimpleChangelog printing" begin - v = VersionInfo("1.0.0", nothing, Date("2024-12-27"), ["One change"], OrderedDict("Section" => ["c1"])) + v = VersionInfo("1.0.0", nothing, Date("2024-12-27"), ["One change"], ["Section" => ["c1"]]) v_str = repr("text/plain", v) @test contains(v_str, "- version: 1.0.0") @test contains(v_str, "- date: 2024-12-27") diff --git a/test/parse_changelog.jl b/test/parse_changelog.jl index 7fe8086..4fdbed2 100644 --- a/test/parse_changelog.jl +++ b/test/parse_changelog.jl @@ -112,8 +112,7 @@ end @test ver_1p1.version == "1.1.0" @test ver_1p1.url == "https://github.com/JuliaDocs/Changelog.jl/releases/tag/v1.1.0" @test ver_1p1.date == Date("2023-11-13") - @test only(keys(ver_1p1.sectioned_changes)) == "Added" - @test ver_1p1.sectioned_changes["Added"] == ["Links of the form `[]`, where `` is a commit hashof length 7 or 40, are now linkified. (#4)"] + @test ver_1p1.sectioned_changes == ["Added" => ["Links of the form `[]`, where `` is a commit hashof length 7 or 40, are now linkified. (#4)"]] @test ver_1p0.version == "1.0.0" @test ver_1p0.url == "https://github.com/JuliaDocs/Changelog.jl/releases/tag/v1.0.0"