From ed705802a387f8209511dfce66acb8e37327ce8e Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Tue, 16 Mar 2021 22:10:42 +0000 Subject: [PATCH 01/15] Implement `fixup` function --- src/PkgTemplates.jl | 12 +++++++++++- src/fixup.jl | 14 ++++++++++++++ src/plugin.jl | 11 +++++++++++ src/plugins/documenter.jl | 3 +++ src/plugins/git.jl | 10 ++++++++++ src/plugins/license.jl | 4 ++++ src/plugins/project_file.jl | 4 ++++ src/plugins/src_dir.jl | 3 +++ 8 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/fixup.jl diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 8c9ae6d8..29d06f22 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -38,7 +38,8 @@ export SrcDir, TagBot, Tests, - TravisCI + TravisCI, + fixup """ Plugins are PkgTemplates' source of customization and extensibility. @@ -48,10 +49,19 @@ When implementing a new plugin, subtype this type to have full control over its """ abstract type Plugin end +""" + isfixable(::Plugin, pkg_dir) -> Bool + +Determines whether or not the plugin can be updated on an existing project via +[`fixup`](@ref). +""" +isfixable(::Plugin, pkg_dir) = false + include("template.jl") include("plugin.jl") include("show.jl") include("interactive.jl") +include("fixup.jl") include("deprecated.jl") # Run some function with a project activated at the given path. diff --git a/src/fixup.jl b/src/fixup.jl new file mode 100644 index 00000000..85282be1 --- /dev/null +++ b/src/fixup.jl @@ -0,0 +1,14 @@ +function fixup(tpl::Template, pkg_dir::AbstractString) + ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) + isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) + + fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) + foreach((prehook, hook, posthook)) do h + @info "Running $(nameof(h))s" + foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p + @info p + h(p, tpl, pkg_dir) + end + end + # TODO: some magic to add badges to an existing Readme?! +end diff --git a/src/plugin.jl b/src/plugin.jl index c6c6eed4..ba2a59a7 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -210,6 +210,17 @@ This function **must** be implemented. """ function destination end +""" + isfixable(p::FilePlugin) -> Bool + +Determines whether or not [`fixup`](@ref) should update the files created by `p`. + +By default, returns `true` if the [`destination(p)`](@ref) file does not exist. +Subtype of [`FilePlugin`](@ref) should implement their own method if they require +different behaviour. +""" +isfixable(p::FilePlugin, pkg_dir) = !isfile(joinpath(pkg_dir, destination(p))) + """ Badge(hover::AbstractString, image::AbstractString, link::AbstractString) diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index 2f321659..359a6660 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -161,6 +161,9 @@ function validate(p::Documenter{T}, t::Template) where T <: YesDeploy end end +# Do not edit existing docs. +isfixable(::Documenter, pkg_dir) = !isdir(joinpath(pkg_dir, "docs")) + function hook(p::Documenter, t::Template, pkg_dir::AbstractString) pkg = basename(pkg_dir) docs_dir = joinpath(pkg_dir, "docs") diff --git a/src/plugins/git.jl b/src/plugins/git.jl index 5b235d56..be15f781 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -54,6 +54,16 @@ function validate(p::Git, t::Template) end end +# fixup only if pkg_dir not a git repo +function isfixable(::Git, pkg_dir) + try + r = GitRepo(pkg_dir) + return !isa(r, GitRepo) + catch + return true + end +end + # Set up the Git repository. function prehook(p::Git, t::Template, pkg_dir::AbstractString) LibGit2.with(LibGit2.init(pkg_dir)) do repo diff --git a/src/plugins/license.jl b/src/plugins/license.jl index 656fb16b..e5bbf248 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -40,6 +40,10 @@ view(::License, t::Template, ::AbstractString) = Dict( "YEAR" => year(today()), ) +function isfixable(::License, pkg_dir) + return !any(isfile, joinpath.(pkg_dir, ("LICENSE", "LICENSE.md"))) +end + function prompt(::Type{License}, ::Type, ::Val{:name}) options = readdir(default_file("licenses")) # Move MIT to the top. diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 28efd583..665e9035 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -38,3 +38,7 @@ function compat_version(v::VersionNumber) "$(v.major).$(v.minor).$(v.patch)" end end + +function isfixable(::ProjectFile, pkg_dir) + return !any(isfile, joinpath.(pkg_dir, ("Project.toml", "JuliaProject.toml"))) +end diff --git a/src/plugins/src_dir.jl b/src/plugins/src_dir.jl index e6004e08..41fb2a57 100644 --- a/src/plugins/src_dir.jl +++ b/src/plugins/src_dir.jl @@ -29,3 +29,6 @@ view(::SrcDir, ::Template, pkg::AbstractString) = Dict("PKG" => pkg) function prehook(p::SrcDir, t::Template, pkg_dir::AbstractString) p.destination = joinpath("src", basename(pkg_dir) * ".jl") end + +# TODO: should this return `true` if `src/` exists but `src/pkg_name.jl` doesn't? +isfixable(p::SrcDir, pkg_dir) = false From 03edd6087cf72b2590ea8c67a872733f06c73be3 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Fri, 4 Jun 2021 16:27:41 +0100 Subject: [PATCH 02/15] Handle directory having `.jl` suffix --- src/fixup.jl | 5 +++-- src/plugins/project_file.jl | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fixup.jl b/src/fixup.jl index 85282be1..78e6dfbb 100644 --- a/src/fixup.jl +++ b/src/fixup.jl @@ -1,4 +1,5 @@ -function fixup(tpl::Template, pkg_dir::AbstractString) +function fixup(tpl::Template, pkg_dir) + pkg_dir = realpath(pkg_dir) ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) @@ -6,9 +7,9 @@ function fixup(tpl::Template, pkg_dir::AbstractString) foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p - @info p h(p, tpl, pkg_dir) end end + @info "Fixed up package at $pkg_dir" # TODO: some magic to add badges to an existing Readme?! end diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 665e9035..ff78b892 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -15,7 +15,9 @@ priority(::ProjectFile, ::typeof(hook)) = typemax(Int) - 5 function hook(p::ProjectFile, t::Template, pkg_dir::AbstractString) toml = Dict( - "name" => basename(pkg_dir), + "name" => let pkg = basename(pkg_dir) + endswith(pkg, ".jl") ? pkg[1:end-3] : pkg + end, "uuid" => string(uuid4()), "authors" => t.authors, "version" => string(p.version), From 7be318cb27df7d1bd73c0ffda4fe8bf2c3b0f067 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Fri, 19 Jul 2024 18:17:33 +0200 Subject: [PATCH 03/15] basic things added. Currently not using CondaPkg, instead relying on new Julia engine since v1.5 --- src/PkgTemplates.jl | 1 + src/plugin.jl | 1 + src/plugins/ci.jl | 1 + src/plugins/quarto.jl | 52 ++++++++++++++++++++++ templates/github/workflows/CI.yml | 47 ++++++++++++++++++++ templates/quarto/README.qmd | 25 +++++++++++ templates/quarto/_quarto.yml | 13 ++++++ templates/quarto/index.qmd | 14 ++++++ templates/quarto/make.jl | 72 +++++++++++++++++++++++++++++++ 9 files changed, 226 insertions(+) create mode 100644 src/plugins/quarto.jl create mode 100644 templates/quarto/README.qmd create mode 100644 templates/quarto/_quarto.yml create mode 100644 templates/quarto/index.qmd create mode 100644 templates/quarto/make.jl diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 1013a41c..7e0e8e34 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -40,6 +40,7 @@ export PkgBenchmark, PkgEvalBadge, ProjectFile, + Quarto, Readme, RegisterAction, Secret, diff --git a/src/plugin.jl b/src/plugin.jl index ac465d3c..cababd0e 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -388,3 +388,4 @@ include(joinpath("plugins", "register.jl")) include(joinpath("plugins", "dependabot.jl")) include(joinpath("plugins", "formatter.jl")) include(joinpath("plugins", "pkgbenchmark.jl")) +include(joinpath("plugins", "quarto.jl")) diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index 129d98b9..4bd09271 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -82,6 +82,7 @@ function view(p::GitHubActions, t::Template, pkg::AbstractString) "HAS_CODECOV" => p.coverage && hasplugin(t, Codecov), "HAS_COVERALLS" => p.coverage && hasplugin(t, Coveralls), "HAS_DOCUMENTER" => hasplugin(t, Documenter{GitHubActions}), + "HAS_QUARTO" => hasplugin(t, Quarto), "HAS_EXCLUDES" => !isempty(excludes), "OS" => os, "PKG" => pkg, diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl new file mode 100644 index 00000000..e100fac4 --- /dev/null +++ b/src/plugins/quarto.jl @@ -0,0 +1,52 @@ +""" + Quarto(; + index_qmd::String = default_file("quarto", "index.qmd") + readme_qmd::String = default_file("quarto", "README.qmd") + config::String = default_file("quarto", "_quarto.yml") + ) +""" +@plugin struct Quarto <: Plugin + index_qmd::String = default_file("quarto", "index.qmd") + readme_qmd::String = default_file("quarto", "README.qmd") + make_jl::String = default_file("quarto", "make.jl") + config::String = default_file("quarto", "_quarto.yml") +end + +PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) = Dict( + "AUTHORS" => join(t.authors, ", "), + "PKG" => pkg, + "REPO" => "$(t.host)/$(t.user)/$pkg.jl", + "USER" => t.user, +) + +function PkgTemplates.validate(p::Quarto, t::Template) + if PkgTemplates.hasplugin(t, Documenter) + # Overwrite make.jl file path (dirty solution) + doc_plugin = t.plugins[findall(typeof.(t.plugins) .<: Documenter)][1] + @assert doc_plugin.make_jl == p.make_jl "make.jl file path mismatch between Quarto and Documenter plugin. When using the Quarto plugin, make sure that the Documenter plugin points to $(p.make_jl)" + end +end + +function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) + + pkg = pkg_name(pkg_dir) + docs_dir = joinpath(pkg_dir, "docs") + assets_dir = joinpath(docs_dir, "src", "assets") + ispath(assets_dir) || mkpath(assets_dir) + + # Readme file: + readme = render_file(p.readme_qmd, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(pkg_dir, "README.qmd"), readme) + + # Index file: + index = render_file(p.index_qmd, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(docs_dir, "src", "index.qmd"), index) + + # Make.jl: + makejl = render_file(p.make_jl, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(docs_dir, "make.jl"), makejl) + + # Config file: + config = render_file(p.config, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(pkg_dir, "_quarto.yml"), config) +end \ No newline at end of file diff --git a/templates/github/workflows/CI.yml b/templates/github/workflows/CI.yml index 351ae847..c1572f07 100644 --- a/templates/github/workflows/CI.yml +++ b/templates/github/workflows/CI.yml @@ -101,3 +101,50 @@ jobs: DocMeta.setdocmeta!(<<&PKG>>, :DocTestSetup, :(using <<&PKG>>); recursive=true) doctest(<<&PKG>>) <> + <<#HAS_QUARTO>> + docs: + name: Documentation + runs-on: ubuntu-latest + permissions: + actions: write # needed to allow julia-actions/cache to proactively delete old caches that it has created + contents: write + statuses: write + steps: + - uses: actions/checkout@v4 + - uses: quarto-dev/quarto-actions/setup@v2 + with: + version: 1.5.54 + - uses: julia-actions/setup-julia@latest + with: + version: '1' + - uses: julia-actions/cache@v2 + - name: Cache Quarto + id: cache-quarto + uses: actions/cache@v3 + env: + cache-name: cache-quarto + with: + path: _freeze + key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('*.qmd') }} + restore-keys: | + ${{ runner.os }}-${{ env.cache-name }}- + - name: Configure doc environment + shell: julia --project=docs --color=yes {0} + run: | + using Pkg + Pkg.develop(PackageSpec(path=pwd())) + Pkg.instantiate() + - uses: julia-actions/julia-buildpkg@v1 + - name: "Documenter rendering (including Quarto)" + run: "docs/make.jl --quarto" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} + - name: Run doctests + shell: julia --project=docs --color=yes {0} + run: | + using Documenter: DocMeta, doctest + using <<&PKG>> + DocMeta.setdocmeta!(<<&PKG>>, :DocTestSetup, :(using <<&PKG>>); recursive=true) + doctest(<<&PKG>>) + <> diff --git a/templates/quarto/README.qmd b/templates/quarto/README.qmd new file mode 100644 index 00000000..63b0118f --- /dev/null +++ b/templates/quarto/README.qmd @@ -0,0 +1,25 @@ +--- +format: + commonmark: + variant: -raw_html+tex_math_dollars + wrap: none + mermaid-format: png +crossref: + fig-prefix: Figure + tbl-prefix: Table +output: asis +--- + +# {{{PKG}}}{{#HAS_INLINE_BADGES}} {{#BADGES}}{{{.}}} {{/BADGES}}{{/HAS_INLINE_BADGES}} +{{^HAS_INLINE_BADGES}} + +{{#BADGES}} +{{{.}}} +{{/BADGES}} +{{/HAS_INLINE_BADGES}} +{{#HAS_CITATION}} + +## Citing + +See [`CITATION.bib`](CITATION.bib) for the relevant reference(s). +{{/HAS_CITATION}} \ No newline at end of file diff --git a/templates/quarto/_quarto.yml b/templates/quarto/_quarto.yml new file mode 100644 index 00000000..da563178 --- /dev/null +++ b/templates/quarto/_quarto.yml @@ -0,0 +1,13 @@ +project: + title: "{{{PKG}}}.jl" + execute-dir: project +crossref: + fig-prefix: Figure + tbl-prefix: Table +resource-path: + - docs/src/assets +format: + commonmark: + variant: -raw_html+tex_math_dollars + wrap: preserve + mermaid-format: png \ No newline at end of file diff --git a/templates/quarto/index.qmd b/templates/quarto/index.qmd new file mode 100644 index 00000000..15f3a87f --- /dev/null +++ b/templates/quarto/index.qmd @@ -0,0 +1,14 @@ +```@meta +CurrentModule = {{{PKG}}} +``` + +# {{{PKG}}} + +Documentation for [{{{PKG}}}](https://{{{REPO}}}). + +```@index +``` + +```@autodocs +Modules = [{{{PKG}}}] +``` \ No newline at end of file diff --git a/templates/quarto/make.jl b/templates/quarto/make.jl new file mode 100644 index 00000000..85c39d19 --- /dev/null +++ b/templates/quarto/make.jl @@ -0,0 +1,72 @@ +#!/usr/bin/env Julia +# +# + +if "--help" ∈ ARGS + println( + """ +docs/make.jl + +Render the documentation using Quarto with optional arguments + +Arguments +* `--help` - print this help and exit without rendering the documentation +* `--prettyurls` – toggle the prettyurls part to true (which is otherwise only true on CI) +* `--quarto` – run the Quarto notebooks from the `tutorials/` folder before generating the documentation + this has to be run locally at least once for the `tutorials/*.md` files to exist that are included in + the documentation (see `--exclude-tutorials`) for the alternative. + If they are generated once they are cached accordingly. + Then you can spare time in the rendering by not passing this argument. + If quarto is not run, some tutorials are generated as empty files, since they + are referenced from within the documentation. +""", + ) + exit(0) +end + +# (a) Did someone say render? +if "--quarto" ∈ ARGS + @info "Rendering Quarto" + run(`quarto render $(@__DIR__)`) +end + +using {{{PKG}}} +using Documenter + +DocMeta.setdocmeta!({{{PKG}}}, :DocTestSetup, :(using {{{PKG}}}); recursive=true) + +makedocs(; + modules=[{{{PKG}}}], + authors="{{{AUTHORS}}}", + sitename="{{{PKG}}}.jl", + format=Documenter.HTML(; +{{#CANONICAL}} + canonical="{{{CANONICAL}}}", +{{/CANONICAL}} +{{#EDIT_LINK}} + edit_link={{{EDIT_LINK}}}, +{{/EDIT_LINK}} + assets={{^HAS_ASSETS}}String{{/HAS_ASSETS}}[{{^HAS_ASSETS}}],{{/HAS_ASSETS}} +{{#ASSETS}} + "assets/{{{.}}}", +{{/ASSETS}} +{{#HAS_ASSETS}} + ], +{{/HAS_ASSETS}} + ), + pages=[ + "Home" => "index.md", + ], +{{#MAKEDOCS_KWARGS}} + {{{first}}}={{{second}}}, +{{/MAKEDOCS_KWARGS}} +) +{{#HAS_DEPLOY}} + +deploydocs(; + repo="{{{REPO}}}", +{{#BRANCH}} + devbranch="{{{BRANCH}}}", +{{/BRANCH}} +) +{{/HAS_DEPLOY}} From bdaa22a6723aae4c0dd1d4b3f3507f361d30efd6 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Fri, 19 Jul 2024 18:29:48 +0200 Subject: [PATCH 04/15] adjusted CI --- src/plugins/ci.jl | 2 +- templates/github/workflows/CI.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index 4bd09271..123fe444 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -81,7 +81,7 @@ function view(p::GitHubActions, t::Template, pkg::AbstractString) "EXCLUDES" => excludes, "HAS_CODECOV" => p.coverage && hasplugin(t, Codecov), "HAS_COVERALLS" => p.coverage && hasplugin(t, Coveralls), - "HAS_DOCUMENTER" => hasplugin(t, Documenter{GitHubActions}), + "HAS_DOCUMENTER" => hasplugin(t, Documenter{GitHubActions}) && !hasplugin(t, Quarto), "HAS_QUARTO" => hasplugin(t, Quarto), "HAS_EXCLUDES" => !isempty(excludes), "OS" => os, diff --git a/templates/github/workflows/CI.yml b/templates/github/workflows/CI.yml index c1572f07..d448d9ec 100644 --- a/templates/github/workflows/CI.yml +++ b/templates/github/workflows/CI.yml @@ -102,7 +102,7 @@ jobs: doctest(<<&PKG>>) <> <<#HAS_QUARTO>> - docs: + docs: name: Documentation runs-on: ubuntu-latest permissions: From 37e6c77776ee8d758f05d81fb1a63c3138321601 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 23 Jul 2024 09:55:40 +0200 Subject: [PATCH 05/15] turn make.jl into executable --- templates/quarto/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 templates/quarto/make.jl diff --git a/templates/quarto/make.jl b/templates/quarto/make.jl old mode 100644 new mode 100755 index 85c39d19..21d62935 --- a/templates/quarto/make.jl +++ b/templates/quarto/make.jl @@ -1,4 +1,4 @@ -#!/usr/bin/env Julia +#!/usr/bin/env julia # # From 0d9c0a78f313e5ab45fcd51ae687c31e352b644b Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 23 Jul 2024 10:31:54 +0200 Subject: [PATCH 06/15] add argument to allow user to specify julia environment when executing the make.jl --- templates/quarto/make.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/templates/quarto/make.jl b/templates/quarto/make.jl index 21d62935..5313a0f6 100755 --- a/templates/quarto/make.jl +++ b/templates/quarto/make.jl @@ -12,6 +12,7 @@ Render the documentation using Quarto with optional arguments Arguments * `--help` - print this help and exit without rendering the documentation * `--prettyurls` – toggle the prettyurls part to true (which is otherwise only true on CI) +* `--project` - specify the project name (default: `$(@__DIR__)`) * `--quarto` – run the Quarto notebooks from the `tutorials/` folder before generating the documentation this has to be run locally at least once for the `tutorials/*.md` files to exist that are included in the documentation (see `--exclude-tutorials`) for the alternative. @@ -24,7 +25,19 @@ Arguments exit(0) end -# (a) Did someone say render? +# (a) Specify project +using Pkg +if any(contains.(ARGS, "--project")) + @assert sum(contains.(ARGS, "--project")) == 1 "Only one environment can be specified using the `--project` argument." + _path = + ARGS[findall(contains.(ARGS, "--project"))][1] |> + x -> replace(x, "--project=" => "") + Pkg.activate(_path) +else + Pkg.activate(@__DIR__) +end + +# (b) Did someone say render? if "--quarto" ∈ ARGS @info "Rendering Quarto" run(`quarto render $(@__DIR__)`) From a816109d13fd6167d9eb3e80b9b304169cb4e777 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 23 Jul 2024 10:58:50 +0200 Subject: [PATCH 07/15] command to turn make.jl into executable --- src/plugins/quarto.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index e100fac4..da05277d 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -12,6 +12,10 @@ config::String = default_file("quarto", "_quarto.yml") end +function isfixable(::Quarto, pkg_dir) + return true +end + PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) = Dict( "AUTHORS" => join(t.authors, ", "), "PKG" => pkg, @@ -45,6 +49,7 @@ function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) # Make.jl: makejl = render_file(p.make_jl, combined_view(p, t, pkg), tags(p)) gen_file(joinpath(docs_dir, "make.jl"), makejl) + run(`chmod u+x $(joinpath(docs_dir, "make.jl"))`) # turn into executable # Config file: config = render_file(p.config, combined_view(p, t, pkg), tags(p)) From cc8ba0335b81d0c0e52bffa2c6b5d03872667b50 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 23 Jul 2024 11:46:18 +0200 Subject: [PATCH 08/15] dont render .md files --- templates/quarto/_quarto.yml | 2 ++ templates/quarto/make.jl | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/quarto/_quarto.yml b/templates/quarto/_quarto.yml index da563178..ba8ce3d8 100644 --- a/templates/quarto/_quarto.yml +++ b/templates/quarto/_quarto.yml @@ -1,6 +1,8 @@ project: title: "{{{PKG}}}.jl" execute-dir: project + render: + - "!docs/src/*.md" crossref: fig-prefix: Figure tbl-prefix: Table diff --git a/templates/quarto/make.jl b/templates/quarto/make.jl index 5313a0f6..e9a6330d 100755 --- a/templates/quarto/make.jl +++ b/templates/quarto/make.jl @@ -39,8 +39,10 @@ end # (b) Did someone say render? if "--quarto" ∈ ARGS - @info "Rendering Quarto" - run(`quarto render $(@__DIR__)`) + @info "Rendering README" + run(`quarto render $(joinpath(@__DIR__, "..", "README.qmd"))`) + @info "Rendering docs" + run(`quarto render $(joinpath(@__DIR__, "src"))`) end using {{{PKG}}} From 6aba90b396b178b81081c6bfba4c8480434ead84 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 09:34:15 +0200 Subject: [PATCH 09/15] ensuring badges are added by using view from Readme plugin --- src/plugins/quarto.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index da05277d..27576734 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -39,7 +39,13 @@ function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) ispath(assets_dir) || mkpath(assets_dir) # Readme file: - readme = render_file(p.readme_qmd, combined_view(p, t, pkg), tags(p)) + if PkgTemplates.hasplugin(t, Readme) + p_readme = t.plugins[findall(typeof.(t.plugins) .<: Readme)][1] + v = merge(combined_view(p, t, pkg), combined_view(p_readme, t, pkg)) # merge views from both plugins + else + v = combined_view(p, t, pkg) + end + readme = render_file(p.readme_qmd, v, tags(p)) gen_file(joinpath(pkg_dir, "README.qmd"), readme) # Index file: From 0605355427640e04c780b483c55520a50cf0596f Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 10:01:29 +0200 Subject: [PATCH 10/15] rendering README locally --- src/plugins/quarto.jl | 37 +++++++++++++++++++++++-------------- templates/quarto/make.jl | 2 -- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index 27576734..457d2492 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -16,12 +16,24 @@ function isfixable(::Quarto, pkg_dir) return true end -PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) = Dict( - "AUTHORS" => join(t.authors, ", "), - "PKG" => pkg, - "REPO" => "$(t.host)/$(t.user)/$pkg.jl", - "USER" => t.user, -) +function PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) + + v = Dict{AbstractString,Any}() + + # Inherit view from Readme plugin: + if PkgTemplates.hasplugin(t, Readme) + p_readme = t.plugins[findall(typeof.(t.plugins) .<: Readme)][1] + v = merge(v, combined_view(p_readme, t, pkg)) + end + + # Inherit view from Documenter plugin: + if PkgTemplates.hasplugin(t, Documenter) + p_doc = t.plugins[findall(typeof.(t.plugins) .<: Documenter)][1] + v = merge(v, combined_view(p_doc, t, pkg)) + end + + return v +end function PkgTemplates.validate(p::Quarto, t::Template) if PkgTemplates.hasplugin(t, Documenter) @@ -39,14 +51,11 @@ function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) ispath(assets_dir) || mkpath(assets_dir) # Readme file: - if PkgTemplates.hasplugin(t, Readme) - p_readme = t.plugins[findall(typeof.(t.plugins) .<: Readme)][1] - v = merge(combined_view(p, t, pkg), combined_view(p_readme, t, pkg)) # merge views from both plugins - else - v = combined_view(p, t, pkg) - end - readme = render_file(p.readme_qmd, v, tags(p)) - gen_file(joinpath(pkg_dir, "README.qmd"), readme) + readme = render_file(p.readme_qmd, combined_view(p, t, pkg), tags(p)) + _file = joinpath(pkg_dir, "README.qmd") + gen_file(_file, readme) + @info "Rendering README" + run(`quarto render $_file`) # Index file: index = render_file(p.index_qmd, combined_view(p, t, pkg), tags(p)) diff --git a/templates/quarto/make.jl b/templates/quarto/make.jl index e9a6330d..ab913d24 100755 --- a/templates/quarto/make.jl +++ b/templates/quarto/make.jl @@ -39,8 +39,6 @@ end # (b) Did someone say render? if "--quarto" ∈ ARGS - @info "Rendering README" - run(`quarto render $(joinpath(@__DIR__, "..", "README.qmd"))`) @info "Rendering docs" run(`quarto render $(joinpath(@__DIR__, "src"))`) end From d76e38197226c5e9661ada863d7f0863ef4b77b2 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 10:51:04 +0200 Subject: [PATCH 11/15] small fix to _quarto.yml --- templates/quarto/_quarto.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/quarto/_quarto.yml b/templates/quarto/_quarto.yml index ba8ce3d8..8985ce9d 100644 --- a/templates/quarto/_quarto.yml +++ b/templates/quarto/_quarto.yml @@ -2,6 +2,7 @@ project: title: "{{{PKG}}}.jl" execute-dir: project render: + - "*.qmd" - "!docs/src/*.md" crossref: fig-prefix: Figure From 68e6dbb53b486a43b5274e06b3c4abc0880b5e0e Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 13:29:26 +0200 Subject: [PATCH 12/15] formatting --- src/PkgTemplates.jl | 6 ++--- src/deprecated.jl | 4 +-- src/fixup.jl | 2 +- src/interactive.jl | 37 ++++++++++++++----------- src/plugin.jl | 23 +++++++++------- src/plugins/badges.jl | 2 +- src/plugins/ci.jl | 9 ++++--- src/plugins/codeowners.jl | 12 ++++++--- src/plugins/coverage.jl | 12 ++++----- src/plugins/develop.jl | 2 +- src/plugins/documenter.jl | 54 ++++++++++++++++++------------------- src/plugins/formatter.jl | 8 ++++-- src/plugins/git.jl | 12 +++++---- src/plugins/license.jl | 14 +++++----- src/plugins/project_file.jl | 5 +++- src/plugins/quarto.jl | 4 +-- src/plugins/readme.jl | 2 +- src/plugins/tagbot.jl | 20 +++++++------- src/plugins/tests.jl | 16 ++++++----- src/show.jl | 4 +-- src/template.jl | 38 +++++++++++++------------- 21 files changed, 155 insertions(+), 131 deletions(-) diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 7e0e8e34..87993486 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -1,5 +1,4 @@ -@doc read(joinpath(dirname(@__DIR__), "README.md"), String) -module PkgTemplates +@doc read(joinpath(dirname(@__DIR__), "README.md"), String) module PkgTemplates using Base: active_project, contractuser @@ -15,8 +14,7 @@ using Parameters: @with_kw_noshow using Mocking -export - Template, +export Template, AppVeyor, BlueStyleBadge, CirrusCI, diff --git a/src/deprecated.jl b/src/deprecated.jl index 9c640256..217c0a02 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,6 +1,6 @@ @deprecate generate(t::Template, pkg::AbstractString) t(pkg) @deprecate generate(pkg::AbstractString, t::Template) t(pkg) -@deprecate interactive_template() Template(; interactive=true) -@deprecate generate_interactive(pkg::AbstractString) Template(; interactive=true)(pkg) +@deprecate interactive_template() Template(; interactive = true) +@deprecate generate_interactive(pkg::AbstractString) Template(; interactive = true)(pkg) @deprecate GitHubPages(; kwargs...) Documenter{TravisCI}(; kwargs...) @deprecate GitLabPages(; kwargs...) Documenter{GitLabCI}(; kwargs...) diff --git a/src/fixup.jl b/src/fixup.jl index 78e6dfbb..2ba58461 100644 --- a/src/fixup.jl +++ b/src/fixup.jl @@ -6,7 +6,7 @@ function fixup(tpl::Template, pkg_dir) fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" - foreach(sort(fixable; by=p -> priority(p, h), rev=true)) do p + foreach(sort(fixable; by = p -> priority(p, h), rev = true)) do p h(p, tpl, pkg_dir) end end diff --git a/src/interactive.jl b/src/interactive.jl index 7f003a8f..60d07d54 100644 --- a/src/interactive.jl +++ b/src/interactive.jl @@ -4,8 +4,8 @@ Shortcut for `Template(; interactive=true)(pkg)`. If no package name is supplied, you will be prompted for one. """ -function generate(pkg::AbstractString=prompt(Template, String, :pkg)) - t = Template(; interactive=true) +function generate(pkg::AbstractString = prompt(Template, String, :pkg)) + t = Template(; interactive = true) t(pkg) return t end @@ -17,7 +17,7 @@ Interactively create a plugin of type `T`. Implement this method and ignore othe related functions only if you want completely custom behaviour. """ function interactive(T::Type) - pairs = Vector{Pair{Symbol, Type}}(interactive_pairs(T)) + pairs = Vector{Pair{Symbol,Type}}(interactive_pairs(T)) # There must be at least 2 MultiSelectMenu options. # If there are none, return immediately. @@ -34,13 +34,13 @@ function interactive(T::Type) "$k" end end - menu = MultiSelectMenu(opts; pagesize=length(pairs)) + menu = MultiSelectMenu(opts; pagesize = length(pairs)) customize = sort!(collect(request(menu))) # If the "None" option was selected, don't customize anything. just_one && lastindex(pairs) in customize && return T() - kwargs = Dict{Symbol, Any}() + kwargs = Dict{Symbol,Any}() foreach(pairs[customize]) do (name, F) kwargs[name] = prompt(T, F, name) end @@ -64,7 +64,7 @@ function pretty_message(s::AbstractString) r"Array{(.*?),1}" => s"Vector{\1}", r"Union{Nothing, (.*?)}" => s"Union{\1, Nothing}", ] - return reduce((s, p) -> replace(s, p), replacements; init=s) + return reduce((s, p) -> replace(s, p), replacements; init = s) end """ @@ -73,12 +73,12 @@ end Provide some extra tips to users on how to structure their input for the type `T`, for example if multiple delimited values are expected. """ -input_tips(::Type{Vector{T}}) where T = [input_tips(T)..., "comma-delimited"] -input_tips(::Type{Union{T, Nothing}}) where T = [input_tips(T)..., input_tips(Nothing)...] +input_tips(::Type{Vector{T}}) where {T} = [input_tips(T)..., "comma-delimited"] +input_tips(::Type{Union{T,Nothing}}) where {T} = [input_tips(T)..., input_tips(Nothing)...] input_tips(::Type{Nothing}) = ["'nothing' for nothing"] input_tips(::Type{Secret}) = ["name only"] # Show expected input type as a tip if it's anything other than `String` -input_tips(::Type{T}) where T = String[string(T)] +input_tips(::Type{T}) where {T} = String[string(T)] input_tips(::Type{String}) = String[] input_tips(::Type{<:Signed}) = ["Int"] # Specific Int type likely not important @@ -91,7 +91,7 @@ A default implementation of `T(s)` exists. convert_input(::Type, T::Type{<:Real}, s::AbstractString) = parse(T, s) convert_input(::Type, T::Type, s::AbstractString) = T(s) -function convert_input(P::Type, ::Type{Union{T, Nothing}}, s::AbstractString) where T +function convert_input(P::Type, ::Type{Union{T,Nothing}}, s::AbstractString) where {T} # This is kind of sketchy because technically, there might be some other input # whose value we want to instantiate with the string "nothing", # but I think that would be a pretty rare occurrence. @@ -99,11 +99,15 @@ function convert_input(P::Type, ::Type{Union{T, Nothing}}, s::AbstractString) wh return s == "nothing" ? nothing : convert_input(P, T, s) end -function convert_input(P::Type, ::Type{Union{T, Symbol, Nothing}}, s::AbstractString) where T +function convert_input( + P::Type, + ::Type{Union{T,Symbol,Nothing}}, + s::AbstractString, +) where {T} # Assume inputs starting with ':' char are intended as Symbols, if a plugin accept symbols. # i.e. assume the set of valid Symbols the plugin expects can be spelt starting with ':'. return if startswith(s, ":") - Symbol(chop(s, head=1, tail=0)) # remove ':' + Symbol(chop(s, head = 1, tail = 0)) # remove ':' else convert_input(P, Union{T,Nothing}, s) end @@ -140,7 +144,7 @@ Implement this method to customize particular fields of particular types. prompt(P::Type, T::Type, name::Symbol) = prompt(P, T, Val(name)) # The trailing `nothing` is a hack for `fallback_prompt` to use, ignore it. -function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing=nothing) where {T, name} +function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing = nothing) where {T,name} default = defaultkw(P, name) tips = join([input_tips(T); "default: $(input_string(default))"], ", ") input = Base.prompt(pretty_message("Enter value for '$name' ($tips)")) @@ -170,8 +174,9 @@ function prompt(P::Type, ::Type{T}, ::Val{name}, ::Nothing=nothing) where {T, na end # Compute all the concrete subtypes of T. -concretes_rec(T::Type) = isabstracttype(T) ? vcat(map(concretes_rec, subtypes(T))...) : Any[T] -concretes(T::Type) = sort!(concretes_rec(T); by=nameof) +concretes_rec(T::Type) = + isabstracttype(T) ? vcat(map(concretes_rec, subtypes(T))...) : Any[T] +concretes(T::Type) = sort!(concretes_rec(T); by = nameof) # Compute name => type pairs for T's interactive options. function interactive_pairs(T::Type) @@ -181,7 +186,7 @@ function interactive_pairs(T::Type) prepend!(pairs, reverse(customizable(T))) uniqueby!(first, pairs) filter!(p -> last(p) !== NotCustomizable, pairs) - sort!(pairs; by=first) + sort!(pairs; by = first) return pairs end diff --git a/src/plugin.jl b/src/plugin.jl index cababd0e..62f4f65e 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -1,5 +1,6 @@ const DEFAULT_PRIORITY = 1000 -const DEFAULT_TEMPLATE_DIR = Ref{String}(joinpath(dirname(dirname(pathof(PkgTemplates))), "templates")) +const DEFAULT_TEMPLATE_DIR = + Ref{String}(joinpath(dirname(dirname(pathof(PkgTemplates))), "templates")) """ @plugin struct ... end @@ -64,7 +65,11 @@ macro plugin(ex::Expr) msg = "Run `using PkgTemplates: @with_kw_noshow` before using this macro" @assert isdefined(__module__, Symbol("@with_kw_noshow")) msg - block = :(begin @with_kw_noshow $ex end) + block = :( + begin + @with_kw_noshow $ex + end + ) foreach(filter(arg -> arg isa Expr, ex.args[3].args)) do field @assert field.head === :(=) "Field must have a default value" @@ -77,7 +82,7 @@ macro plugin(ex::Expr) return esc(block) end -function Base.:(==)(a::T, b::T) where T <: Plugin +function Base.:(==)(a::T, b::T) where {T<:Plugin} return all(n -> getfield(a, n) == getfield(b, n), fieldnames(T)) end @@ -122,7 +127,7 @@ but you can always call it yourself as part of your [`hook`](@ref) implementatio By default, an empty `Dict` is returned. """ -view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() +view(::Plugin, ::Template, ::AbstractString) = Dict{String,Any}() """ user_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} @@ -132,7 +137,7 @@ The same as [`view`](@ref), but for use by package *users* for extension. Values returned by this function will override those from [`view`](@ref) when the keys are the same. """ -user_view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() +user_view(::Plugin, ::Template, ::AbstractString) = Dict{String,Any}() """ combined_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} @@ -296,7 +301,7 @@ At this point, both the [`prehook`](@ref)s and [`hook`](@ref)s have run. """ posthook(::Plugin, ::Template, ::AbstractString) = nothing -function validate(p::T, ::Template) where T <: FilePlugin +function validate(p::T, ::Template) where {T<:FilePlugin} src = source(p) src === nothing && return isfile(src) || throw(ArgumentError("$(nameof(T)): The file $src does not exist")) @@ -333,7 +338,7 @@ Render a template file with the data in `view`. `tags` should be a tuple of two strings, which are the opening and closing delimiters, or `nothing` to use the default delimiters. """ -function render_file(file::AbstractString, view::Dict{<:AbstractString}, tags=nothing) +function render_file(file::AbstractString, view::Dict{<:AbstractString}, tags = nothing) return render_text(read(file, String), view, tags) end @@ -344,8 +349,8 @@ Render some text with the data in `view`. `tags` should be a tuple of two strings, which are the opening and closing delimiters, or `nothing` to use the default delimiters. """ -function render_text(text::AbstractString, view::Dict{<:AbstractString}, tags=nothing) - return tags === nothing ? render(text, view) : render(text, view; tags=tags) +function render_text(text::AbstractString, view::Dict{<:AbstractString}, tags = nothing) + return tags === nothing ? render(text, view) : render(text, view; tags = tags) end """ diff --git a/src/plugins/badges.jl b/src/plugins/badges.jl index 075a24fe..562e1118 100644 --- a/src/plugins/badges.jl +++ b/src/plugins/badges.jl @@ -46,7 +46,7 @@ function badges(::PkgEvalBadge) return Badge( "PkgEval", "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.svg", - "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.html" + "https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/{{{PKG1}}}/{{{PKG}}}.html", ) end diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index 123fe444..ac85bb87 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -73,7 +73,7 @@ function view(p::GitHubActions, t::Template, pkg::AbstractString) p.osx && push!(os, "macOS-latest") p.windows && push!(os, "windows-latest") arch = filter(a -> getfield(p, Symbol(a)), ["x64", "x86"]) - excludes = Dict{String, String}[] + excludes = Dict{String,String}[] p.osx && p.x86 && push!(excludes, Dict("E_OS" => "macOS-latest", "E_ARCH" => "x86")) v = Dict( @@ -81,7 +81,8 @@ function view(p::GitHubActions, t::Template, pkg::AbstractString) "EXCLUDES" => excludes, "HAS_CODECOV" => p.coverage && hasplugin(t, Codecov), "HAS_COVERALLS" => p.coverage && hasplugin(t, Coveralls), - "HAS_DOCUMENTER" => hasplugin(t, Documenter{GitHubActions}) && !hasplugin(t, Quarto), + "HAS_DOCUMENTER" => + hasplugin(t, Documenter{GitHubActions}) && !hasplugin(t, Quarto), "HAS_QUARTO" => hasplugin(t, Quarto), "HAS_EXCLUDES" => !isempty(excludes), "OS" => os, @@ -150,7 +151,7 @@ function view(p::TravisCI, t::Template, pkg::AbstractString) versions = collect_versions(t, p.extra_versions) allow_failures = filter(in(versions), ALLOWED_FAILURES) - excludes = Dict{String, String}[] + excludes = Dict{String,String}[] p.x86 && p.osx && push!(excludes, Dict("E_OS" => "osx", "E_ARCH" => "x86")) if p.arm64 p.osx && push!(excludes, Dict("E_OS" => "osx", "E_ARCH" => "arm64")) @@ -417,7 +418,7 @@ function collect_versions(t::Template, versions::Vector) return sort(unique(vs)) end -const AllCI = Union{AppVeyor, GitHubActions, TravisCI, CirrusCI, GitLabCI, DroneCI} +const AllCI = Union{AppVeyor,GitHubActions,TravisCI,CirrusCI,GitLabCI,DroneCI} """ is_ci(::Plugin) -> Bool diff --git a/src/plugins/codeowners.jl b/src/plugins/codeowners.jl index 44244f8d..4eb8b002 100644 --- a/src/plugins/codeowners.jl +++ b/src/plugins/codeowners.jl @@ -29,10 +29,16 @@ end function PkgTemplates.validate(p::CodeOwners, ::Template) for (pattern, subowners) in p.owners - contains(pattern, r"\s") && throw(ArgumentError(("Pattern ($pattern) must not contain whitespace"))) + contains(pattern, r"\s") && + throw(ArgumentError(("Pattern ($pattern) must not contain whitespace"))) for subowner in subowners - contains(subowner, r"\s") && throw(ArgumentError("Owner name ($subowner) must not contain whitespace")) - '@' ∈ subowner || throw(ArgumentError("Owner name ($subowner) must be `@user` or `email@domain.com`")) + contains(subowner, r"\s") && + throw(ArgumentError("Owner name ($subowner) must not contain whitespace")) + '@' ∈ subowner || throw( + ArgumentError( + "Owner name ($subowner) must be `@user` or `email@domain.com`", + ), + ) end end end diff --git a/src/plugins/coverage.jl b/src/plugins/coverage.jl index ae9fb5ec..c0460796 100644 --- a/src/plugins/coverage.jl +++ b/src/plugins/coverage.jl @@ -10,7 +10,7 @@ Sets up code coverage submission from CI to [Codecov](https://codecov.io). or `nothing` to create no file. """ @plugin struct Codecov <: FilePlugin - file::Union{String, Nothing} = nothing + file::Union{String,Nothing} = nothing end source(p::Codecov) = p.file @@ -32,7 +32,7 @@ Sets up code coverage submission from CI to [Coveralls](https://coveralls.io). or `nothing` to create no file. """ @plugin struct Coveralls <: FilePlugin - file::Union{String, Nothing} = nothing + file::Union{String,Nothing} = nothing end source(p::Coveralls) = p.file @@ -44,8 +44,8 @@ badges(::Coveralls) = Badge( "https://coveralls.io/github/{{{USER}}}/{{{PKG}}}.jl?branch={{{BRANCH}}}", ) -gitignore(::Union{Codecov, Coveralls}) = COVERAGE_GITIGNORE -view(::Union{Codecov, Coveralls}, t::Template, pkg::AbstractString) = Dict( +gitignore(::Union{Codecov,Coveralls}) = COVERAGE_GITIGNORE +view(::Union{Codecov,Coveralls}, t::Template, pkg::AbstractString) = Dict( "BRANCH" => something(default_branch(t), DEFAULT_DEFAULT_BRANCH), "PKG" => pkg, "USER" => t.user, @@ -58,6 +58,6 @@ Determine whether or not a plugin is a coverage plugin. If you are adding a coverage plugin, you should implement this function and return `true`. """ is_coverage(::Plugin) = false -is_coverage(::Union{Codecov, Coveralls}) = true +is_coverage(::Union{Codecov,Coveralls}) = true -needs_username(::Union{Codecov, Coveralls}) = true +needs_username(::Union{Codecov,Coveralls}) = true diff --git a/src/plugins/develop.jl b/src/plugins/develop.jl index 835f2717..eb1628cb 100644 --- a/src/plugins/develop.jl +++ b/src/plugins/develop.jl @@ -9,5 +9,5 @@ for more details. struct Develop <: Plugin end function posthook(::Develop, ::Template, pkg_dir::AbstractString) - Pkg.develop(PackageSpec(; path=pkg_dir)) + Pkg.develop(PackageSpec(; path = pkg_dir)) end diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index eb67ce60..72682ce5 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -1,11 +1,9 @@ -const DOCUMENTER_DEP = PackageSpec(; - name="Documenter", - uuid="e30172f5-a6a5-5a46-863b-614d45cd2de4", -) +const DOCUMENTER_DEP = + PackageSpec(; name = "Documenter", uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4") struct NoDeploy end -const YesDeploy = Union{TravisCI, GitHubActions, GitLabCI} -const GitHubPagesStyle = Union{TravisCI, GitHubActions} +const YesDeploy = Union{TravisCI,GitHubActions,GitLabCI} +const GitHubPagesStyle = Union{TravisCI,GitHubActions} """ Logo(; light=nothing, dark=nothing) @@ -17,8 +15,8 @@ Logo information for documentation. - `dark::AbstractString`: Path to a logo file for the dark theme. """ @with_kw_noshow struct Logo - light::Union{String, Nothing} = nothing - dark::Union{String, Nothing} = nothing + light::Union{String,Nothing} = nothing + dark::Union{String,Nothing} = nothing end """ @@ -76,23 +74,23 @@ struct Documenter{T} <: Plugin assets::Vector{String} logo::Logo makedocs_kwargs::Dict{Symbol} - canonical_url::Union{Function, Nothing} + canonical_url::Union{Function,Nothing} make_jl::String index_md::String - devbranch::Union{String, Nothing} - edit_link::Union{String, Symbol, Nothing} + devbranch::Union{String,Nothing} + edit_link::Union{String,Symbol,Nothing} end # Can't use @plugin because we're implementing our own no-arguments constructor. function Documenter{T}(; - assets::Vector{<:AbstractString}=String[], - logo::Logo=Logo(), - makedocs_kwargs::Dict{Symbol}=Dict{Symbol, Any}(), - canonical_url::Union{Function, Nothing}=make_canonical(T), - make_jl::AbstractString=default_file("docs", "make.jl"), - index_md::AbstractString=default_file("docs", "src", "index.md"), - devbranch::Union{AbstractString, Nothing}=nothing, - edit_link::Union{AbstractString, Symbol, Nothing}=:devbranch, + assets::Vector{<:AbstractString} = String[], + logo::Logo = Logo(), + makedocs_kwargs::Dict{Symbol} = Dict{Symbol,Any}(), + canonical_url::Union{Function,Nothing} = make_canonical(T), + make_jl::AbstractString = default_file("docs", "make.jl"), + index_md::AbstractString = default_file("docs", "src", "index.md"), + devbranch::Union{AbstractString,Nothing} = nothing, + edit_link::Union{AbstractString,Symbol,Nothing} = :devbranch, ) where {T} return Documenter{T}( assets, @@ -146,12 +144,14 @@ function view(p::Documenter, t::Template, pkg::AbstractString) "AUTHORS" => join(t.authors, ", "), "CANONICAL" => p.canonical_url === nothing ? nothing : p.canonical_url(t, pkg), "HAS_ASSETS" => !isempty(p.assets), - "MAKEDOCS_KWARGS" => map(((k, v),) -> k => repr(v), sort(collect(p.makedocs_kwargs), by=first)), + "MAKEDOCS_KWARGS" => + map(((k, v),) -> k => repr(v), sort(collect(p.makedocs_kwargs), by = first)), "PKG" => pkg, "REPO" => "$(t.host)/$(t.user)/$pkg.jl", "USER" => t.user, "BRANCH" => devbranch, - "EDIT_LINK" => p.edit_link == :devbranch ? _quoted(devbranch) : _quoted(p.edit_link), + "EDIT_LINK" => + p.edit_link == :devbranch ? _quoted(devbranch) : _quoted(p.edit_link), ) end @@ -160,7 +160,7 @@ _quoted(s::AbstractString) = string('"', s, '"') _quoted(s::Symbol) = repr(s) function view(p::Documenter{<:GitHubPagesStyle}, t::Template, pkg::AbstractString) - base = invoke(view, Tuple{Documenter, Template, AbstractString}, p, t, pkg) + base = invoke(view, Tuple{Documenter,Template,AbstractString}, p, t, pkg) return merge(base, Dict("HAS_DEPLOY" => true)) end @@ -176,8 +176,8 @@ function validate(p::Documenter, ::Template) end end -function validate(p::Documenter{T}, t::Template) where T <: YesDeploy - invoke(validate, Tuple{Documenter, Template}, p, t) +function validate(p::Documenter{T}, t::Template) where {T<:YesDeploy} + invoke(validate, Tuple{Documenter,Template}, p, t) if !hasplugin(t, T) name = nameof(T) s = "Documenter: The $name plugin must be included for docs deployment to be set up" @@ -214,7 +214,7 @@ function hook(p::Documenter, t::Template, pkg_dir::AbstractString) # Create the documentation project. with_project(docs_dir) do Pkg.add(DOCUMENTER_DEP) - cd(() -> Pkg.develop(PackageSpec(; path="..")), docs_dir) + cd(() -> Pkg.develop(PackageSpec(; path = "..")), docs_dir) end end @@ -233,7 +233,7 @@ end function interactive(::Type{Documenter}) styles = [NoDeploy, TravisCI, GitLabCI, GitHubActions] - menu = RadioMenu(map(string, styles); pagesize=length(styles)) + menu = RadioMenu(map(string, styles); pagesize = length(styles)) println("Documenter deploy style:") idx = request(menu) return interactive(Documenter{styles[idx]}) @@ -242,5 +242,5 @@ end function prompt(::Type{<:Documenter}, ::Type{Logo}, ::Val{:logo}) light = Base.prompt("Enter value for 'logo.light' (default: nothing)") dark = Base.prompt("Enter value for 'logo.dark' (default: nothing)") - return Logo(; light=light, dark=dark) + return Logo(; light = light, dark = dark) end diff --git a/src/plugins/formatter.jl b/src/plugins/formatter.jl index afaace9f..ce5fcaa5 100644 --- a/src/plugins/formatter.jl +++ b/src/plugins/formatter.jl @@ -19,7 +19,11 @@ end function validate(p::Formatter, t::Template) if p.style ∉ ("nostyle", "blue", "sciml", "yas") - throw(ArgumentError("""JuliaFormatter style must be either "nostyle", "blue", "sciml" or "yas".""")) + throw( + ArgumentError( + """JuliaFormatter style must be either "nostyle", "blue", "sciml" or "yas".""", + ), + ) end end @@ -38,7 +42,7 @@ end function prompt(::Type{Formatter}, ::Type{String}, ::Val{:style}) options = ["nostyle", "blue", "sciml", "yas"] - menu = RadioMenu(options; pagesize=length(options)) + menu = RadioMenu(options; pagesize = length(options)) println("Select a JuliaFormatter style:") idx = request(menu) return options[idx] diff --git a/src/plugins/git.jl b/src/plugins/git.jl index 6550728a..fd006a93 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -30,8 +30,8 @@ Creates a Git repository and a `.gitignore` file. """ @plugin struct Git <: Plugin ignore::Vector{String} = String[] - name::Union{String, Nothing} = nothing - email::Union{String, Nothing} = nothing + name::Union{String,Nothing} = nothing + email::Union{String,Nothing} = nothing branch::String = @mock(LibGit2.getconfig("init.defaultBranch", DEFAULT_DEFAULT_BRANCH)) ssh::Bool = false jl::Bool = true @@ -51,7 +51,9 @@ function validate(p::Git, t::Template) foreach((:name, :email)) do k user_k = "user.$k" if getproperty(p, k) === nothing && isempty(@mock LibGit2.getconfig(user_k, "")) - throw(ArgumentError("Git: Global Git config is missing required value '$user_k'")) + throw( + ArgumentError("Git: Global Git config is missing required value '$user_k'"), + ) end end end @@ -128,7 +130,7 @@ end function commit(p::Git, repo::GitRepo, pkg_dir::AbstractString, msg::AbstractString) if p.gpgsign - run(pipeline(`git -C $pkg_dir commit -S --allow-empty -m $msg`; stdout=devnull)) + run(pipeline(`git -C $pkg_dir commit -S --allow-empty -m $msg`; stdout = devnull)) else LibGit2.commit(repo, msg) end @@ -138,7 +140,7 @@ needs_username(::Git) = true function git_is_installed() return try - run(pipeline(`git --version`; stdout=devnull)) + run(pipeline(`git --version`; stdout = devnull)) true catch false diff --git a/src/plugins/license.jl b/src/plugins/license.jl index fc82da8e..a5baa7ed 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -18,9 +18,9 @@ struct License <: FilePlugin end function License(; - name::AbstractString="MIT", - path::Union{AbstractString, Nothing}=nothing, - destination::AbstractString="LICENSE", + name::AbstractString = "MIT", + path::Union{AbstractString,Nothing} = nothing, + destination::AbstractString = "LICENSE", ) if path === nothing path = default_file("licenses", name) @@ -35,10 +35,8 @@ defaultkw(::Type{License}, ::Val{:destination}) = "LICENSE" source(p::License) = p.path destination(p::License) = p.destination -view(::License, t::Template, ::AbstractString) = Dict( - "AUTHORS" => join(t.authors, ", "), - "YEAR" => year(today()), -) +view(::License, t::Template, ::AbstractString) = + Dict("AUTHORS" => join(t.authors, ", "), "YEAR" => year(today())) function isfixable(::License, pkg_dir) return !any(isfile, joinpath.(pkg_dir, ("LICENSE", "LICENSE.md"))) @@ -49,7 +47,7 @@ function prompt(::Type{License}, ::Type, ::Val{:name}) # Move MIT to the top. deleteat!(options, findfirst(==("MIT"), options)) pushfirst!(options, "MIT") - menu = RadioMenu(options; pagesize=length(options)) + menu = RadioMenu(options; pagesize = length(options)) println("Select a license:") idx = request(menu) return options[idx] diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 7e5b5918..197c23c8 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -29,7 +29,10 @@ end function project_key_order(key::String) _project_key_order = ["name", "uuid", "keywords", "license", "desc", "deps", "compat"] - return something(findfirst(x -> x == key, _project_key_order), length(_project_key_order) + 1) + return something( + findfirst(x -> x == key, _project_key_order), + length(_project_key_order) + 1, + ) end write_project(path::AbstractString, dict) = diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index 457d2492..91af0b7b 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -23,7 +23,7 @@ function PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) # Inherit view from Readme plugin: if PkgTemplates.hasplugin(t, Readme) p_readme = t.plugins[findall(typeof.(t.plugins) .<: Readme)][1] - v = merge(v, combined_view(p_readme, t, pkg)) + v = merge(v, combined_view(p_readme, t, pkg)) end # Inherit view from Documenter plugin: @@ -69,4 +69,4 @@ function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) # Config file: config = render_file(p.config, combined_view(p, t, pkg), tags(p)) gen_file(joinpath(pkg_dir, "_quarto.yml"), config) -end \ No newline at end of file +end diff --git a/src/plugins/readme.jl b/src/plugins/readme.jl index 35fa2f15..bfa00190 100644 --- a/src/plugins/readme.jl +++ b/src/plugins/readme.jl @@ -63,5 +63,5 @@ default_badge_order() = [ CirrusCI, Codecov, Coveralls, - subtypes(BadgePlugin)... + subtypes(BadgePlugin)..., ] diff --git a/src/plugins/tagbot.jl b/src/plugins/tagbot.jl index 190c3399..11734e1b 100644 --- a/src/plugins/tagbot.jl +++ b/src/plugins/tagbot.jl @@ -39,16 +39,16 @@ Adds GitHub release support via [TagBot](https://github.com/JuliaRegistries/TagB destination::String = "TagBot.yml" trigger::String = "JuliaTagBot" token::Secret = Secret("GITHUB_TOKEN") - ssh::Union{Secret, Nothing} = Secret("DOCUMENTER_KEY") - ssh_password::Union{Secret, Nothing} = nothing - changelog::Union{String, Nothing} = nothing - changelog_ignore::Union{Vector{String}, Nothing} = nothing - gpg::Union{Secret, Nothing} = nothing - gpg_password::Union{Secret, Nothing} = nothing - registry::Union{String, Nothing} = nothing - branches::Union{Bool, Nothing} = nothing - dispatch::Union{Bool, Nothing} = nothing - dispatch_delay::Union{Int, Nothing} = nothing + ssh::Union{Secret,Nothing} = Secret("DOCUMENTER_KEY") + ssh_password::Union{Secret,Nothing} = nothing + changelog::Union{String,Nothing} = nothing + changelog_ignore::Union{Vector{String},Nothing} = nothing + gpg::Union{Secret,Nothing} = nothing + gpg_password::Union{Secret,Nothing} = nothing + registry::Union{String,Nothing} = nothing + branches::Union{Bool,Nothing} = nothing + dispatch::Union{Bool,Nothing} = nothing + dispatch_delay::Union{Int,Nothing} = nothing end source(p::TagBot) = p.file diff --git a/src/plugins/tests.jl b/src/plugins/tests.jl index 0aa06eff..5f4bccaf 100644 --- a/src/plugins/tests.jl +++ b/src/plugins/tests.jl @@ -1,11 +1,11 @@ const TEST_UUID = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -const TEST_DEP = PackageSpec(; name="Test", uuid=TEST_UUID) +const TEST_DEP = PackageSpec(; name = "Test", uuid = TEST_UUID) const AQUA_UUID = "4c88cf16-eb10-579e-8560-4a9242c79595" -const AQUA_DEP = PackageSpec(; name="Aqua", uuid=AQUA_UUID) +const AQUA_DEP = PackageSpec(; name = "Aqua", uuid = AQUA_UUID) const JET_UUID = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" -const JET_DEP = PackageSpec(; name="JET", uuid=JET_UUID) +const JET_DEP = PackageSpec(; name = "JET", uuid = JET_UUID) """ Tests(; @@ -76,7 +76,9 @@ end function validate(p::Tests, t::Template) invoke(validate, Tuple{FilePlugin,Template}, p, t) - p.project && t.julia < v"1.2" && @warn string( + p.project && + t.julia < v"1.2" && + @warn string( "Tests: The project option is set to create a project (supported in Julia 1.2 and later) ", "but a Julia version older than 1.2 ($(t.julia)) is supported by the template", ) @@ -127,7 +129,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) # Add the dependency manually since there's no programmatic way to add to [extras]. path = joinpath(pkg_dir, "Project.toml") toml = TOML.parsefile(path) - + get!(toml, "extras", Dict())["Test"] = TEST_UUID if p.aqua get!(toml, "extras", Dict())["Aqua"] = AQUA_UUID @@ -135,7 +137,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) if p.jet get!(toml, "extras", Dict())["JET"] = JET_UUID end - + targets = String[] if p.aqua push!(targets, "Aqua") @@ -145,7 +147,7 @@ function add_test_dependency(p::Tests, pkg_dir::AbstractString) end push!(targets, "Test") get!(toml, "targets", Dict())["test"] = targets - + write_project(path, toml) # Generate the manifest by updating the project. diff --git a/src/show.jl b/src/show.jl index 85f2b83e..95e3e591 100644 --- a/src/show.jl +++ b/src/show.jl @@ -7,14 +7,14 @@ function Base.show(io::IO, m::MIME"text/plain", t::Template) print(io, " plugins: None") else print(io, repeat(' ', 2), "plugins:") - foreach(sort(t.plugins; by=string)) do p + foreach(sort(t.plugins; by = string)) do p println(io) show(IOContext(io, :indent => 4), m, p) end end end -function Base.show(io::IO, ::MIME"text/plain", p::T) where T <: Plugin +function Base.show(io::IO, ::MIME"text/plain", p::T) where {T<:Plugin} indent = get(io, :indent, 0) print(io, repeat(' ', indent), nameof(T)) ns = fieldnames(T) diff --git a/src/template.jl b/src/template.jl index f60f6dba..fed09936 100644 --- a/src/template.jl +++ b/src/template.jl @@ -22,7 +22,7 @@ function default_authors() end struct MissingUserException{T} <: Exception end -function Base.showerror(io::IO, ::MissingUserException{T}) where T +function Base.showerror(io::IO, ::MissingUserException{T}) where {T} s = """$(nameof(T)): Git hosting service username is required, set one with keyword `user=""`""" print(io, s) end @@ -80,7 +80,7 @@ struct Template user::String end -Template(; interactive::Bool=false, kwargs...) = Template(Val(interactive); kwargs...) +Template(; interactive::Bool = false, kwargs...) = Template(Val(interactive); kwargs...) Template(::Val{true}; kwargs...) = interactive(Template; kwargs...) function Template(::Val{false}; kwargs...) @@ -102,7 +102,7 @@ function Template(::Val{false}; kwargs...) !(typeof(p) in vcat(typeof.(plugins), disabled)) end append!(plugins, defaults) - plugins = Vector{Plugin}(sort(plugins; by=string)) + plugins = Vector{Plugin}(sort(plugins; by = string)) if isempty(user) foreach(plugins) do p @@ -135,12 +135,12 @@ function (t::Template)(pkg::AbstractString) try foreach((prehook, hook, posthook)) do h @info "Running $(nameof(h))s" - foreach(sort(t.plugins; by=p -> priority(p, h), rev=true)) do p + foreach(sort(t.plugins; by = p -> priority(p, h), rev = true)) do p h(p, t, pkg_dir) end end catch - rm(pkg_dir; recursive=true, force=true) + rm(pkg_dir; recursive = true, force = true) rethrow() end @@ -159,23 +159,23 @@ end function Base.:(==)(a::Template, b::Template) return a.authors == b.authors && - a.dir == b.dir && - a.host == b.host && - a.julia == b.julia && - a.user == b.user && - all(map(==, a.plugins, b.plugins)) + a.dir == b.dir && + a.host == b.host && + a.julia == b.julia && + a.user == b.user && + all(map(==, a.plugins, b.plugins)) end # Does the template have a plugin that satisfies some predicate? hasplugin(t::Template, f::Function) = any(f, t.plugins) -hasplugin(t::Template, ::Type{T}) where T <: Plugin = hasplugin(t, p -> p isa T) +hasplugin(t::Template, ::Type{T}) where {T<:Plugin} = hasplugin(t, p -> p isa T) """ getplugin(t::Template, ::Type{T<:Plugin}) -> Union{T, Nothing} Get the plugin of type `T` from the template `t`, if it's present. """ -function getplugin(t::Template, ::Type{T}) where T <: Plugin +function getplugin(t::Template, ::Type{T}) where {T<:Plugin} i = findfirst(p -> p isa T, t.plugins) return i === nothing ? nothing : t.plugins[i] end @@ -184,7 +184,7 @@ end getkw!(kwargs, k) = pop!(kwargs, k, defaultkw(Template, k)) # Default Template keyword values. -defaultkw(::Type{T}, s::Symbol) where T = defaultkw(T, Val(s)) +defaultkw(::Type{T}, s::Symbol) where {T} = defaultkw(T, Val(s)) defaultkw(::Type{Template}, ::Val{:authors}) = default_authors() defaultkw(::Type{Template}, ::Val{:dir}) = contractuser(Pkg.devdir()) defaultkw(::Type{Template}, ::Val{:host}) = "github.com" @@ -194,7 +194,7 @@ defaultkw(::Type{Template}, ::Val{:user}) = default_user() function interactive(::Type{Template}; kwargs...) # If the user supplied any keywords themselves, don't prompt for them. - kwargs = Dict{Symbol, Any}(kwargs) + kwargs = Dict{Symbol,Any}(kwargs) options = [:user, :authors, :dir, :host, :julia, :plugins] customizable = setdiff(options, keys(kwargs)) @@ -205,8 +205,8 @@ function interactive(::Type{Template}; kwargs...) try println("Template keywords to customize:") - opts = map(k -> "$k ($(repr(defaultkw(Template, k))))" , customizable) - menu = MultiSelectMenu(opts; pagesize=length(customizable)) + opts = map(k -> "$k ($(repr(defaultkw(Template, k))))", customizable) + menu = MultiSelectMenu(opts; pagesize = length(customizable)) customize = customizable[sort!(collect(request(menu)))] just_one && last(customizable) in customize && return Template(; kwargs...) @@ -245,7 +245,7 @@ end function prompt(::Type{Template}, ::Type, ::Val{:host}) hosts = ["github.com", "gitlab.com", "bitbucket.org", "Other"] - menu = RadioMenu(hosts; pagesize=length(hosts)) + menu = RadioMenu(hosts; pagesize = length(hosts)) println("Select Git repository hosting service:") idx = request(menu) return if idx == lastindex(hosts) @@ -258,7 +258,7 @@ end function prompt(::Type{Template}, ::Type, ::Val{:julia}) versions = map(format_version, VersionNumber.(1, 0:VERSION.minor)) push!(versions, "Other") - menu = RadioMenu(map(string, versions); pagesize=length(versions)) + menu = RadioMenu(map(string, versions); pagesize = length(versions)) println("Select minimum Julia version:") idx = request(menu) return if idx == lastindex(versions) @@ -276,7 +276,7 @@ function prompt(::Type{Template}, ::Type, ::Val{:plugins}) ndefaults = length(defaults) # Put the defaults first. options = unique!([defaults; concretes(Plugin)]) - menu = MultiSelectMenu(map(T -> string(nameof(T)), options); pagesize=length(options)) + menu = MultiSelectMenu(map(T -> string(nameof(T)), options); pagesize = length(options)) println("Select plugins:") # Pre-select the default plugins and move the cursor to the first non-default. # To make this better, we need julia#30043. From 3b84af03437cce31041206adf37448fff9c7962c Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 13:44:05 +0200 Subject: [PATCH 13/15] dealing with Quarto README in case of fixup --- src/plugins/quarto.jl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index 91af0b7b..48a0b50f 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -39,7 +39,7 @@ function PkgTemplates.validate(p::Quarto, t::Template) if PkgTemplates.hasplugin(t, Documenter) # Overwrite make.jl file path (dirty solution) doc_plugin = t.plugins[findall(typeof.(t.plugins) .<: Documenter)][1] - @assert doc_plugin.make_jl == p.make_jl "make.jl file path mismatch between Quarto and Documenter plugin. When using the Quarto plugin, make sure that the Documenter plugin points to $(p.make_jl)" + @assert doc_plugin.make_jl == p.make_jl "make.jl file path mismatch between Quarto and Documenter plugin. When using the Quarto plugin, make sure that the Documenter plugin points to $(p.make_jl), i.e. use `Documenter(make_jl=Quarto().make_jl)`" end end @@ -52,10 +52,22 @@ function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) # Readme file: readme = render_file(p.readme_qmd, combined_view(p, t, pkg), tags(p)) - _file = joinpath(pkg_dir, "README.qmd") - gen_file(_file, readme) + path = joinpath(pkg_dir, "README.qmd") + mkd_path = replace(path, ".qmd" => ".md") + if isfile(path) + path_fixed = replace(path, ".qmd" => "_fixed.qmd") + @warn "README file already exists at $path. Generating a fixed but empty version from template at $path_fixed. You will most likely just have to copy and paste the content from the existing README into the fixed version and then overwrite $path with $path_fixed." + gen_file(path_fixed, readme) + elseif isfile(mkd_path) + backup_path = replace(mkd_path, ".md" => "_backup.md") + run(`cp $mkd_path $backup_path`) + @warn "Existing `README.md` (markdown) file found and backed up as $backup_path. You may have to copy existing contents into the newly generated Quarto file at $path." + gen_file(path, readme) + else + gen_file(path, readme) + end @info "Rendering README" - run(`quarto render $_file`) + run(`quarto render $path`) # Index file: index = render_file(p.index_qmd, combined_view(p, t, pkg), tags(p)) From 687b77ea94aff607633ea7addc3e54c5c4d1a7a5 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 13:58:14 +0200 Subject: [PATCH 14/15] added docstrings --- src/plugins/quarto.jl | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/plugins/quarto.jl b/src/plugins/quarto.jl index 48a0b50f..3f783928 100644 --- a/src/plugins/quarto.jl +++ b/src/plugins/quarto.jl @@ -12,10 +12,13 @@ config::String = default_file("quarto", "_quarto.yml") end -function isfixable(::Quarto, pkg_dir) - return true -end +isfixable(::Quarto, pkg_dir) = true + +""" + PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) +Overloads the `view` function for the Quarto plugin. The Quarto plugin inherits its view from the `Readme` and `Documenter` plugins. +""" function PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) v = Dict{AbstractString,Any}() @@ -35,6 +38,11 @@ function PkgTemplates.view(p::Quarto, t::Template, pkg::AbstractString) return v end +""" + PkgTemplates.validate(p::Quarto, t::Template) + +Overloads the `validate` function for the Quarto plugin. The method asserts that the `Documenter` plugin (if used) is pointing to the same `make.jl` template file as the `Quarto` plugin. +""" function PkgTemplates.validate(p::Quarto, t::Template) if PkgTemplates.hasplugin(t, Documenter) # Overwrite make.jl file path (dirty solution) @@ -43,6 +51,16 @@ function PkgTemplates.validate(p::Quarto, t::Template) end end +""" + PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) + +Overloads the `hook` function for the Quarto plugin. The Quarto plugin does the following: + +1. It adds a `README.qmd` file and renders a `README.md` file from it (locally). +2. It adds an `index.qmd` file to the `docs/src/` folder (to be rendered remotely). +3. It generates a custom `make.jl` for using Documenter.jl with Quarto. +4. It adds a `_quarto.yml` file that configures Quarto for use with Documenter.jl. +""" function PkgTemplates.hook(p::Quarto, t::Template, pkg_dir::AbstractString) pkg = pkg_name(pkg_dir) From 3910fe6006e3ad037e8e7a5d3ccfaca2d9860e77 Mon Sep 17 00:00:00 2001 From: pat-alt Date: Tue, 27 Aug 2024 15:43:00 +0200 Subject: [PATCH 15/15] trying to undo unrelated fixup things --- src/PkgTemplates.jl | 12 +----------- src/fixup.jl | 15 --------------- src/plugin.jl | 11 ----------- src/plugins/documenter.jl | 3 --- src/plugins/git.jl | 10 ---------- src/plugins/license.jl | 4 ---- src/plugins/project_file.jl | 4 ---- src/plugins/src_dir.jl | 3 --- 8 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 src/fixup.jl diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 87993486..50ae5437 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -45,8 +45,7 @@ export Template, SrcDir, TagBot, Tests, - TravisCI, - fixup + TravisCI """ Plugins are PkgTemplates' source of customization and extensibility. @@ -56,19 +55,10 @@ When implementing a new plugin, subtype this type to have full control over its """ abstract type Plugin end -""" - isfixable(::Plugin, pkg_dir) -> Bool - -Determines whether or not the plugin can be updated on an existing project via -[`fixup`](@ref). -""" -isfixable(::Plugin, pkg_dir) = false - include("template.jl") include("plugin.jl") include("show.jl") include("interactive.jl") -include("fixup.jl") include("deprecated.jl") # Run some function with a project activated at the given path. diff --git a/src/fixup.jl b/src/fixup.jl deleted file mode 100644 index 2ba58461..00000000 --- a/src/fixup.jl +++ /dev/null @@ -1,15 +0,0 @@ -function fixup(tpl::Template, pkg_dir) - pkg_dir = realpath(pkg_dir) - ispath(pkg_dir) || throw(ArgumentError("Not a directory.")) - isdir(joinpath(pkg_dir, "src")) || throw(ArgumentError("No `src/` directory.")) - - fixable = filter(p -> isfixable(p, pkg_dir), tpl.plugins) - foreach((prehook, hook, posthook)) do h - @info "Running $(nameof(h))s" - foreach(sort(fixable; by = p -> priority(p, h), rev = true)) do p - h(p, tpl, pkg_dir) - end - end - @info "Fixed up package at $pkg_dir" - # TODO: some magic to add badges to an existing Readme?! -end diff --git a/src/plugin.jl b/src/plugin.jl index 62f4f65e..9e1c2688 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -215,17 +215,6 @@ This function **must** be implemented. """ function destination end -""" - isfixable(p::FilePlugin) -> Bool - -Determines whether or not [`fixup`](@ref) should update the files created by `p`. - -By default, returns `true` if the [`destination(p)`](@ref) file does not exist. -Subtype of [`FilePlugin`](@ref) should implement their own method if they require -different behaviour. -""" -isfixable(p::FilePlugin, pkg_dir) = !isfile(joinpath(pkg_dir, destination(p))) - """ Badge(hover::AbstractString, image::AbstractString, link::AbstractString) diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index 72682ce5..2b3b32b5 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -185,9 +185,6 @@ function validate(p::Documenter{T}, t::Template) where {T<:YesDeploy} end end -# Do not edit existing docs. -isfixable(::Documenter, pkg_dir) = !isdir(joinpath(pkg_dir, "docs")) - function hook(p::Documenter, t::Template, pkg_dir::AbstractString) pkg = pkg_name(pkg_dir) docs_dir = joinpath(pkg_dir, "docs") diff --git a/src/plugins/git.jl b/src/plugins/git.jl index fd006a93..7007f183 100644 --- a/src/plugins/git.jl +++ b/src/plugins/git.jl @@ -58,16 +58,6 @@ function validate(p::Git, t::Template) end end -# fixup only if pkg_dir not a git repo -function isfixable(::Git, pkg_dir) - try - r = GitRepo(pkg_dir) - return !isa(r, GitRepo) - catch - return true - end -end - # Set up the Git repository. function prehook(p::Git, t::Template, pkg_dir::AbstractString) LibGit2.with(@mock LibGit2.init(pkg_dir)) do repo diff --git a/src/plugins/license.jl b/src/plugins/license.jl index a5baa7ed..74cf423f 100644 --- a/src/plugins/license.jl +++ b/src/plugins/license.jl @@ -38,10 +38,6 @@ destination(p::License) = p.destination view(::License, t::Template, ::AbstractString) = Dict("AUTHORS" => join(t.authors, ", "), "YEAR" => year(today())) -function isfixable(::License, pkg_dir) - return !any(isfile, joinpath.(pkg_dir, ("LICENSE", "LICENSE.md"))) -end - function prompt(::Type{License}, ::Type, ::Val{:name}) options = readdir(default_file("licenses")) # Move MIT to the top. diff --git a/src/plugins/project_file.jl b/src/plugins/project_file.jl index 197c23c8..fe3cf9ee 100644 --- a/src/plugins/project_file.jl +++ b/src/plugins/project_file.jl @@ -54,7 +54,3 @@ function compat_version(v::VersionNumber) "$(v.major).$(v.minor).$(v.patch)" end end - -function isfixable(::ProjectFile, pkg_dir) - return !any(isfile, joinpath.(pkg_dir, ("Project.toml", "JuliaProject.toml"))) -end diff --git a/src/plugins/src_dir.jl b/src/plugins/src_dir.jl index bfe95708..d5ddbe5b 100644 --- a/src/plugins/src_dir.jl +++ b/src/plugins/src_dir.jl @@ -29,6 +29,3 @@ view(::SrcDir, ::Template, pkg::AbstractString) = Dict("PKG" => pkg) function prehook(p::SrcDir, ::Template, pkg_dir::AbstractString) p.destination = joinpath("src", pkg_name(pkg_dir) * ".jl") end - -# TODO: should this return `true` if `src/` exists but `src/pkg_name.jl` doesn't? -isfixable(p::SrcDir, pkg_dir) = false