From 7a2a43f3f485b28efd42682f93831771297ce1a7 Mon Sep 17 00:00:00 2001 From: Chris de Graaf Date: Wed, 18 Sep 2019 21:22:04 +0700 Subject: [PATCH] Lots of documentation changes --- .travis.yml | 6 +- docs/make.jl | 5 +- docs/src/developer.md | 223 ++++++++++++++++++++++++++++++++++++-- docs/src/index.md | 25 +++++ docs/src/user.md | 114 +++++++++++++++++-- src/PkgTemplates.jl | 7 +- src/generate.jl | 16 ++- src/plugin.jl | 92 ++++++---------- src/plugins/ci.jl | 18 +-- src/plugins/citation.jl | 2 +- src/plugins/coverage.jl | 4 +- src/plugins/defaults.jl | 24 ++-- src/plugins/documenter.jl | 2 +- src/template.jl | 14 ++- test/plugin.jl | 1 + 15 files changed, 447 insertions(+), 106 deletions(-) create mode 100644 docs/src/index.md diff --git a/.travis.yml b/.travis.yml index 7246a9f1..a9fdc1ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,9 +28,9 @@ matrix: - stage: Documentation julia: 1.0 script: - - git config --global user.name Your-Name - - git config --global user.email your-email - - git config --global github.user your-username + - git config --global user.name name + - git config --global user.email email + - git config --global github.user username - julia --project=docs -e ' using Pkg; Pkg.develop(PackageSpec(; path=pwd())); diff --git a/docs/make.jl b/docs/make.jl index 3d6900b5..66168486 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,4 +1,4 @@ -using Documenter +using Documenter: Documenter, makedocs, deploydocs using PkgTemplates: PkgTemplates makedocs(; @@ -11,7 +11,8 @@ makedocs(; assets=String[], ), pages=[ - "Home" => "user.md", + "Home" => "index.md", + "User Guide" => "user.md", "Developer Guide" => "developer.md", ], ) diff --git a/docs/src/developer.md b/docs/src/developer.md index 1f9666c2..06a4013f 100644 --- a/docs/src/developer.md +++ b/docs/src/developer.md @@ -4,28 +4,237 @@ CurrentModule = PkgTemplates # PkgTemplates Developer Guide +```@contents +Pages = ["developer.md"] +``` + PkgTemplates can be easily extended by adding new [`Plugin`](@ref)s. -## The `Plugin` Interface +There are two types of plugins: [`Plugin`](@ref) and [`BasicPlugin`](@ref). + +```@docs +Plugin +BasicPlugin +``` + +## `Plugin` Walkthrough + +Concrete types that subtype [`Plugin`](@ref) directly are free to do almost anything. +To understand how they're implemented, let's look at a simplified version of [`Documenter`](@ref): + +```julia +@with_kw_noshow struct Documenter <: Plugin + make_jl::String = default_file("make.jl") + index_md::String = default_file("index.md") +end + +gitignore(::Documenter) = ["/docs/build/", "/docs/site/"] + +badges(::Documenter) = [ + Badge( + "Stable", + "https://img.shields.io/badge/docs-stable-blue.svg", + "https://{{USER}}.github.io/{{PKG}}.jl/stable", + ), + Badge( + "Dev", + "https://img.shields.io/badge/docs-dev-blue.svg", + "https://{{USER}}.github.io/{{PKG}}.jl/dev", + ), +] + +view(p::Documenter, t::Template, pkg::AbstractString) = Dict( + "AUTHORS" => join(t.authors, ", "), + "PKG" => pkg, + "REPO" => "$(t.host)/$(t.user)/$pkg.jl", + "USER" => t.user, +) + +function gen_plugin(p::Documenter, t::Template, pkg_dir::AbstractString) + pkg = basename(pkg_dir) + docs_dir = joinpath(pkg_dir, "docs") + + make = render_file(p.make_jl, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(docs_dir, "make.jl"), make) + + index = render_file(p.index_md, combined_view(p, t, pkg), tags(p)) + gen_file(joinpath(docs_dir, "src", "index.md"), index) + + # What this function does is not relevant here. + create_documentation_project() +end +``` + +First of all, `@with_kw_noshow` comes from [Parameters.jl](https://github.com/mauro3/Parameters.jl), and it just defines a nice keyword constructor for us. +The default values for our type are using [`default_file`](@ref) to point to files in this repository. + +```@docs +default_file +``` + +The first method we implement for `Documenter` is [`gitignore`](@ref), so that packages created with this plugin ignore documentation build artifacts. ```@docs -gen_plugin gitignore +``` + +Second, we implement [`badges`](@ref) to add a couple of badges to new packages' README files. + +```@docs badges Badge +``` + +Third, we implement [`view`](@ref), which is used to fill placeholders in badges and rendered files. + +```@docs view -user_view +``` + +Finally, we implement [`gen_plugin`](@ref), which is the real workhorse for the plugin. + +```@docs +gen_plugin +``` + +Inside of this function, we call a few more functions, which help us with text templating. + +```@docs +render_file +render_text +gen_file combined_view tags ``` -## The `BasicPlugin` Interface +todo more + +## `BasicPlugin` Walkthrough + +Plugins that subtype [`BasicPlugin`](@ref) perform a much more limited task. +In general, they just generate one templated file. + +To illustrate, let's look at the [`Citation`](@ref) plugin, which creates a `CITATION.bib` file. + +```julia +@with_kw_noshow struct Citation <: BasicPlugin + file::String = default_file("CITATION.bib") +end + +source(p::Citation) = p.file +destination(::Citation) = "CITATION.bib" + +tags(::Citation) = "<<", ">>" + +view(::Citation, t::Template, pkg::AbstractString) = Dict( + "AUTHORS" => join(t.authors, ", "), + "MONTH" => month(today()), + "PKG" => pkg, + "URL" => "https://$(t.host)/$(t.user)/$pkg.jl", + "YEAR" => year(today()), +) +``` + +Similar to the `Documenter` example above, we're defining a keyword constructor, and assigning a default template file from this repository. +This plugin adds nothing to `.gitignore`, and it doesn't add any badges, so implementations for [`gitignore`](@ref) and [`badges`](@ref) are omitted. -While subtyping [`Plugin`](@ref) gives you complete freedom, it's not always necessary. -For more constrained cases, a simpler API exists. +First, we implement [`source`](@ref) and [`destination`](@ref) to define where the template file comes from, and where it goes. +These functions are specific to [`BasicPlugin`](@ref)s, and have no effect on regular [`Plugin`](@ref)s by default. ```@docs -BasicPlugin source destination ``` + +Next, we implement [`tags`](@ref). +We briefly saw this function earlier, but in this case it's necessary to change its behaviour from the default. +To see why, it might help to see the template file in its entirety: + +``` +@misc{<>.jl, + author = {<>}, + title = {<>.jl}, + url = {<>}, + version = {v0.1.0}, + year = {<>}, + month = {<>} +} +``` + +Because the file contains its own `{}` delimiters, we need to use different ones for templating to work properly. + +Finally, we implement [`view`](@ref) to fill in the placeholders that we saw in the template file. + +## Doing Extra Work With `BasicPlugin`s + +Notice that we didn't have to implement [`gen_plugin`](@ref) for our plugin. +It's implemented for all [`BasicPlugin`](@ref)s, like so: + +```julia +function render_plugin(p::BasicPlugin, t::Template, pkg::AbstractString) + return render_file(source(p), combined_view(p, t, pkg), tags(p)) +end + +function gen_plugin(p::BasicPlugin, t::Template, pkg_dir::AbstractString) + source(p) === nothing && return + pkg = basename(pkg_dir) + path = joinpath(pkg_dir, destination(p)) + text = render_plugin(p, t, pkg) + gen_file(path, text) +end +``` + +But what if we want to do a little more than just generate one file? + +A good example of this is the [`Tests`](@ref) plugin. +It creates `runtests.jl`, but it also modifies the `Project.toml` to include the `Test` dependency. + +Of course, we could use a normal [`Plugin`](@ref), but it turns out there's a way to avoid that while still getting the extra capbilities that we want. + +The plugin implements its own `gen_plugin`, but uses `invoke` to avoid duplicating the file creation code: + +```julia +@with_kw_noshow struct Tests <: BasicPlugin + file::String = default_file("runtests.jl") +end + +source(p::Tests) = p.file +destination(::Tests) = joinpath("test", "runtests.jl") +view(::Tests, ::Template, pkg::AbstractString) = Dict("PKG" => pkg) + +function gen_plugin(p::Tests, t::Template, pkg_dir::AbstractString) + # Do the normal BasicPlugin behaviour to create the test script. + invoke(gen_plugin, Tuple{BasicPlugin, Template, AbstractString}, p, t, pkg_dir) + # Do some other work. + add_test_dependency() +end +``` + +For more examples, see the plugins in the [Continuous Integration (CI)](@ref) and [Code Coverage](@ref) sections. + +## Miscellaneous Tips + +### Writing Template Files + +For an overview of writing template files for Mustache.jl, see [Custom Template Files](@ref) in the user guide. + +### Traits + +There are a few traits for plugin types that are occassionally used to answer questions like "does this `Template` have any code coverage plugins?". +If you're implementing a plugin that fits into one of the following categories, it would be wise to implement the corresponding trait function to return `true` for your type. + +```@docs +is_ci +is_coverage +``` + +### Formatting Version Numbers + +When writing configuration files for CI services, working with version numbers is often needed. +There are a few convenience functions that can be used to make this a little bit easier. + +```@docs +compat_version +format_version +collect_versions +``` diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 00000000..9b996991 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,25 @@ +```@meta +CurrentModule = PkgTemplates +``` + +# PkgTemplates + +**PkgTemplates creates new Julia packages in an easy, repeatable, and customizable way.** + +### Foreword: Templating vs. Template + +This documentation refers plenty to [`Template`](@ref)s, the package's main type. +But it also refers to "template files" and "text templating", which are plaintext files with placeholders to be filled with data, and the technique of filling those placeholders with data, respectively. + +These concepts should be familiar if you've used [Jinja](https://palletsprojects.com/p/jinja) or [Mustache](https://mustache.github.io) (Mustache is the particular flavour used by PkgTemplates, via [Mustache.jl](https://github.com/jverzani/Mustache.jl)). + +### Documentation + +If you're looking to **create new packages**, see the [User Guide](user.md). + +If you want to **create new plugins**, see the [Developer Guide](developer.md). + +### Index + +```@index +``` diff --git a/docs/src/user.md b/docs/src/user.md index 0d00db2b..c811086e 100644 --- a/docs/src/user.md +++ b/docs/src/user.md @@ -4,6 +4,10 @@ CurrentModule = PkgTemplates # PkgTemplates User Guide +```@contents +Pages = ["user.md"] +``` + Using PkgTemplates is straightforward. Just create a [`Template`](@ref), and call it on a package name to generate that package. @@ -15,16 +19,12 @@ Template ## Plugins -Plugins are PkgTemplates' source of customization and extensibility. -Add plugins to your templates to enable extra pieces of repository setup. - -```@docs -Plugin -``` +Plugins add functionality to `Template`s. +There are a number of plugins available to automate common boilerplate tasks. ### Defaults -These plugins are included in [`Template`](@ref)s by default. +These plugins are included by default. They can be overridden by supplying another value via the `plugins` keyword, or disabled by supplying the type via the `disable_defaults` keyword. ```@docs @@ -66,6 +66,106 @@ Documenter Citation ``` +## Custom Template Files + +Many plugins support a `file` argument or similar, which sets the path to the template file to be used for generating files. +Each plugin has a sensible default that should make sense for most people, but you might have a specialized workflow that requires a totally different template file. + +If that's the case, a basic understanding of [Mustache](https://mustache.github.io)'s syntax is required. +Here's an example template file: + +``` +Hello, {{name}}. + +{{#weather}} +It's {{weather}} outside. +{{/weather}} +{{^weather}} +I don't know what the weather outside is. +{{/weather}} + +{{#has_things}} +I have the following things: +{{/has_things}} +{{#things}} +- Here's a thing: {{.}} +{{/things}} + +{{#people}} +- {{name}} is {{mood}} +{{/people}} +``` + +In the first section, `name` is a key, and its value replaces `{{name}}`. + +In the second section, `weather`'s value may or may not exist. +If it does exist, then "It's $weather outside" is printed. +Otherwise, "I don't know what the weather outside is" is printed. +Mustache uses a notion of "truthiness" similar to Python or JavaScript, where values of `nothing`, `false`, or empty collections are all considered to not exist. + +In the third section, `has_things`' value is printed if it's truthy. +Then, if the `things` list is truthy (i.e. not empty), its values are each printed on their own line. +The reason that we have two separate keys is that `{{#things}}` iterates over the whole `things` list, even when there are no `{{.}}` placeholders, which would duplicate "I have the following things:" `n` times. + +The fourth section iterates over the `people` list, but instead of using the `{{.}}` placeholder, we have `name` and `mood`, which are keys or fields of the list elements. +Most types are supported here, including `Dict`s and structs. +`NamedTuple`s require you to use `{{:name}}` instead of the normal `{{name}}`, though. + +Assuming the following view: + +```julia +struct Person; name::String; mood::String; end +things = ["a", "b", "c"] +view = Dict( + "name" => "Chris", + "weather" => "sunny", + "has_things" => !isempty(things), + "things" => things, + "people" => [Person("John", "happy"), Person("Jane", "sad")], +) +``` + +Our example template would produce this: + +``` +Hello, Chris. + +It's sunny outside. + +I have the following things: +- Here's a thing: a +- Here's a thing: b +- Here's a thing: c + +- John is happy +- Jane is sad +``` + +## Extending Existing Plugins + +Most of the existing plugins generate a file from a template file. +If you want to use custom template files, you may run into situations where the data passed into the templating engine is not sufficient. +In this case, you can look into implementing [`user_view`](@ref) to supply whatever data is necessary for your use case. + +```@docs +user_view +``` + +For example, suppose you were using the [`Readme`](@ref) plugin with a custom template file that looked like this: + +```md +# {{PKG}} + +Created on *{{TODAY}}*. +``` + +The [`view`](@ref) function supplies a value for `PKG`, but it does not supply a value for `TODAY`. +Rather than override [`view`](@ref), we can implement this function to get both the default values and whatever else we need to add. + +```julia +user_view(::Readme, ::Template, ::AbstractString) = Dict("TODAY" => today()) +``` + ## Saving Templates One of the main reasons for PkgTemplates' existence is for new packages to be consistent. diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 81a4a389..d6769d0e 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -5,7 +5,7 @@ using Base.Filesystem: contractuser using Dates: month, today, year using InteractiveUtils: subtypes -using LibGit2: LibGit2 +using LibGit2: LibGit2, GitRemote using Pkg: Pkg, TOML, PackageSpec using REPL.TerminalMenus: MultiSelectMenu, RadioMenu, request @@ -28,7 +28,10 @@ export TravisCI """ -A plugin to be added to a [`Template`](@ref), which adds some functionality or integration. +Plugins are PkgTemplates' source of customization and extensibility. +Add plugins to your [`Template`](@ref)s to enable extra pieces of repository setup. + +When implementing a new plugin, subtype this type to have full control over its behaviour. """ abstract type Plugin end diff --git a/src/generate.jl b/src/generate.jl index 669685be..7a1716d5 100644 --- a/src/generate.jl +++ b/src/generate.jl @@ -31,10 +31,10 @@ function (t::Template)(pkg::AbstractString) else "https://$(t.host)/$(t.user)/$pkg.jl" end - remote = LibGit2.GitRemote(repo, "origin", url) - # TODO: `git pull` still requires some Git branch config. - LibGit2.add_push!(repo, remote, "refs/heads/master") - close(remote) + LibGit2.with(GitRemote(repo, "origin", url)) do remote + # TODO: `git pull` still requires some Git branch config. + LibGit2.add_push!(repo, remote, "refs/heads/master") + end end # Generate the files. @@ -66,10 +66,14 @@ function (t::Template)(pkg::AbstractString) end end -# Format the version to be included in Project.toml's [compat] section. +""" + compat_version(v::VersionNumber) -> String + +Format a `VersionNumber` to exclude trailing zero components. +""" function compat_version(v::VersionNumber) return if v.patch == 0 && v.minor == 0 - string(v.major) + "$(v.major)" elseif v.patch == 0 "$(v.major).$(v.minor)" else diff --git a/src/plugin.jl b/src/plugin.jl index 695e80b7..7d48e503 100644 --- a/src/plugin.jl +++ b/src/plugin.jl @@ -1,31 +1,15 @@ const DEFAULTS_DIR = normpath(joinpath(@__DIR__, "..", "defaults")) -badge_order() = [ - Documenter{GitLabCI}, - Documenter{TravisCI}, - GitLabCI, - TravisCI, - AppVeyor, - CirrusCI, - Codecov, - Coveralls, -] - """ A simple plugin that, in general, creates a single file. - -You needn't implement [`gen_plugin`](@ref) for your subtypes. -Instead, you're left to implement a couple of much simpler functions: - -- [`source`](@ref) -- [`destination`](@ref) - -For examples, see the plugins in the [Continuous Integration (CI)](@ref) and [Code Coverage](@ref) sections. -For an example of a plugin that creates a file and then does some additional work, see [`Tests`](@ref). """ abstract type BasicPlugin <: Plugin end -# Compute the path to a default template file in this repository. +""" + default_file(paths::AbstractString...) -> String + +Return a path relative to the default template file directory (`$(contractuser(DEFAULTS_DIR))`). +""" default_file(paths::AbstractString...) = joinpath(DEFAULTS_DIR, paths...) """ @@ -38,9 +22,6 @@ For [`BasicPlugin`](@ref)s, this is used for both the plugin badges (see [`badge For other [`Plugin`](@ref)s, it is used only for badges, but you can always call it yourself as part of your [`gen_plugin`](@ref) implementation. By default, an empty `Dict` is returned. - -!!! note - For more information on templating with Mustache, see the [Mustache.jl](https://github.com/jverzani/Mustache.jl) documentation. """ view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() @@ -49,34 +30,34 @@ view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() The same as [`view`](@ref), but for use by package *users* for extension. -For example, suppose you were using the [`Readme`](@ref) with a custom template file that looked like this: - -```md -# {{PKG}} - -Created on *{{TODAY}}*. -``` +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}() -The [`view`](@ref) function supplies a value for `PKG`, but it does not supply a value for `TODAY`. -Rather than override [`view`](@ref), we can implement this function to get both the default values and whatever else we need to add. +""" + combined_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} -```julia -user_view(::Readme, ::Template, ::AbstractString) = Dict("TODAY" => today()) -``` +This function combines [`view`](@ref) and [`user_view`](@ref) for use in text templating. +If you're doing manual file creation or text templating (i.e. writing [`Plugin`](@ref)s that are not [`BasicPlugin`](@ref)s), then you should use this function rather than either of the former two. -Values returned by this function will override those from [`view`](@ref) when the keys are the same. +!!! note + Do not implement this function yourself! + If you're implementing a plugin, you should implement [`view`](@ref). + If you're customizing a plugin as a user, you should implement [`user_view`](@ref). """ -user_view(::Plugin, ::Template, ::AbstractString) = Dict{String, Any}() +function combined_view(p::Plugin, t::Template, pkg::AbstractString) + return merge(view(p, t, pkg), user_view(p, t, pkg)) +end """ tags(::Plugin) -> Tuple{String, String} -Return the tags used for Mustache templating. +Return the delimiters used for text templating. See the [`Citation`](@ref) plugin for a rare case where changing the tags is necessary. By default, the tags are `"{{"` and `"}}"`. """ -tags(::Plugin) = ("{{", "}}") +tags(::Plugin) = "{{", "}}" """ gitignore(::Plugin) -> Vector{String} @@ -117,7 +98,7 @@ This function **must** be implemented. function destination end """ - Badge(hover::AbstractString, image::AbstractString, link::AbstractString) -> Badge + Badge(hover::AbstractString, image::AbstractString, link::AbstractString) Container for Markdown badge data. Each argument can contain placeholders (which will be filled in with values from [`combined_view`](@ref)). @@ -164,24 +145,9 @@ function gen_plugin(p::BasicPlugin, t::Template, pkg_dir::AbstractString) end function render_plugin(p::BasicPlugin, t::Template, pkg::AbstractString) - # TODO template rendering code return render_file(source(p), combined_view(p, t, pkg), tags(p)) end -""" - combined_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any} - -This function combines [`view`](@ref) and [`user_view`](@ref) for use in text templating. -If you're doing manual creation (i.e. writing [`Plugin`](@ref)s that are not [`BasicPlugin`](@ref)s, then you should use this function rather than either of the former two. - -!!! note - You should **not** implement this function yourself. -""" -function combined_view(p::Plugin, t::Template, pkg::AbstractString) - return merge(view(p, t, pkg), user_view(p, t, pkg)) -end - - """ gen_file(file::AbstractString, text::AbstractString) @@ -194,12 +160,22 @@ function gen_file(file::AbstractString, text::AbstractString) write(file, text) end -# Render text from a file. +""" + render_file(file::AbstractString view::Dict{<:AbstractString}, tags) -> String + +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) render_text(read(file, String), view, tags) end -# Render text using Mustache's templating system. HTML escaping is disabled. +""" + render_text(text::AbstractString, view::Dict{<:AbstractString}, tags=nothing) -> String + +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) saved = copy(entityMap) empty!(entityMap) diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index 9a43bc5f..9628a1a2 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -1,4 +1,9 @@ -# Strip everything but the major and minor release from a version number. +""" + format_version(v::Union{VersionNumber, AbstractString}) -> String + +Strip everything but the major and minor release from a `VersionNumber`. +Strings are left in their original form. +""" format_version(v::VersionNumber) = "$(v.major).$(v.minor)" format_version(v::AbstractString) = string(v) @@ -6,11 +11,10 @@ const ALLOWED_FAILURES = ["1.3", "nightly"] # TODO: Update this list with new R const DEFAULT_CI_VERSIONS = map(format_version, [default_version(), VERSION, "nightly"]) const EXTRA_VERSIONS_DOC = "- `extra_versions::Vector`: Extra Julia versions to test, as strings or `VersionNumber`s." - """ collect_versions(t::Template, versions::Vector) -> Vector{String} -Combine the [`Template`](@ref)'s Julia version and some other versions, and format them as `major.minor`. +Combine `t`'s Julia version with `versions`, and format them as `major.minor`. This is useful for creating lists of versions to be included in CI configurations. """ function collect_versions(t::Template, versions::Vector) @@ -27,7 +31,7 @@ end x86=false, coverage=true, extra_versions=$DEFAULT_CI_VERSIONS, - ) -> TravisCI + ) Integrates your packages with [Travis CI](https://travis-ci.com). @@ -99,7 +103,7 @@ end x86=false, coverage=true, extra_versions=$DEFAULT_CI_VERSIONS, - ) -> AppVeyor + ) Integrates your packages with [AppVeyor](https://appveyor.com) via [AppVeyor.jl](https://github.com/JuliaCI/Appveyor.jl). @@ -149,7 +153,7 @@ end image="freebsd-12-0-release-amd64", coverage=true, extra_versions=$DEFAULT_CI_VERSIONS, - ) -> CirrusCI + ) Integrates your packages with [Cirrus CI](https://cirrus-ci.org) via [CirrusCI.jl](https://github.com/ararslan/CirrusCI.jl). @@ -195,7 +199,7 @@ end file="$(contractuser(default_file("gitlab-ci.yml")))", coverage=true, extra_versions=$DEFAULT_CI_VERSIONS, - ) -> GitLabCI + ) Integrates your packages with [GitLab CI](https://docs.gitlab.com/ce/ci/). diff --git a/src/plugins/citation.jl b/src/plugins/citation.jl index a52469cd..1f45196c 100644 --- a/src/plugins/citation.jl +++ b/src/plugins/citation.jl @@ -2,7 +2,7 @@ Citation(; file="$(contractuser(default_file("CITATION.bib")))", readme=false, - ) -> Citation + ) Creates a `CITATION.bib` file for citing package repositories. diff --git a/src/plugins/coverage.jl b/src/plugins/coverage.jl index 8d030ef2..04002947 100644 --- a/src/plugins/coverage.jl +++ b/src/plugins/coverage.jl @@ -1,7 +1,7 @@ const COVERAGE_GITIGNORE = ["*.jl.cov", "*.jl.*.cov", "*.jl.mem"] """ - Codecov(; file=nothing) -> Codecov + Codecov(; file=nothing) Sets up code coverage submission from CI to [Codecov](https://codecov.io). @@ -22,7 +22,7 @@ badges(::Codecov) = Badge( ) """ - Coveralls(; file=nothing) -> Coverallls + Coveralls(; file=nothing) Sets up code coverage submission from CI to [Coveralls](https://coveralls.io). diff --git a/src/plugins/defaults.jl b/src/plugins/defaults.jl index 53ea0863..fdc14191 100644 --- a/src/plugins/defaults.jl +++ b/src/plugins/defaults.jl @@ -14,12 +14,23 @@ const LICENSES = Dict( "EUPL-1.2+" => "European Union Public Licence, Version 1.2+", ) +badge_order() = [ + Documenter{GitLabCI}, + Documenter{TravisCI}, + GitLabCI, + TravisCI, + AppVeyor, + CirrusCI, + Codecov, + Coveralls, +] + """ Readme(; file="$(contractuser(default_file("README.md")))", destination="README.md", inline_badges=false, - ) -> Readme, + ) Creates a `README` file. By default, it includes badges for other included plugins @@ -57,14 +68,14 @@ function view(p::Readme, t::Template, pkg::AbstractString) return Dict( "BADGES" => strings, - "HAS_CITATION" => hasplugin(t, Citation), - "HAS_INLINE_BADGES" => !isempty(strings) && p.inline_badges, + "HAS_CITATION" => hasplugin(t, Citation) && t.plugins[Citation].readme, + "HAS_INLINE_BADGES" => !isempty(strings) && p.inline_badges, "PKG" => pkg, ) end """ - License(; name="MIT", destination="LICENSE") -> License + License(; name="MIT", destination="LICENSE") Creates a license file. @@ -90,9 +101,6 @@ function license_path(license::AbstractString) return path end -# Read a license's text. -read_license(license::AbstractString) = string(readchomp(license_path(license))) - function render_plugin(p::License, t::Template) date = year(today()) authors = join(t.authors, ", ") @@ -106,7 +114,7 @@ function gen_plugin(p::License, t::Template, pkg_dir::AbstractString) end """ - Gitignore(; ds_store=true, dev=true) -> Gitignore + Gitignore(; ds_store=true, dev=true) Creates a `.gitignore` file. diff --git a/src/plugins/documenter.jl b/src/plugins/documenter.jl index cf002a9e..dc61dd01 100644 --- a/src/plugins/documenter.jl +++ b/src/plugins/documenter.jl @@ -7,7 +7,7 @@ const DOCUMENTER_UUID = "e30172f5-a6a5-5a46-863b-614d45cd2de4" assets=String[], canonical_url=, makedocs_kwargs=Dict{Symbol, Any}(), - ) -> Documenter{T} + ) Sets up documentation generation via [Documenter.jl](https://github.com/JuliaDocs/Documenter.jl). Documentation deployment depends on `T`, where `T` is some supported CI plugin, or `Nothing` to only support local documentation builds. diff --git a/src/template.jl b/src/template.jl index 37ccdb3a..8ef31542 100644 --- a/src/template.jl +++ b/src/template.jl @@ -10,7 +10,7 @@ function default_authors() end """ - Template(; kwargs...) -> Template + Template(; kwargs...) A configuration used to generate packages. @@ -25,13 +25,13 @@ A configuration used to generate packages. Like `user`, it takes its default value from the global Git config (`user.name` and `user.email`). ### Package Options -- `host::AbstractString="github.com"`: URL to the code hosting service where packages will reside. - `dir::AbstractString="$(contractuser(Pkg.devdir()))"`: Directory to place packages in. - `julia_version::VersionNumber=$(repr(default_version()))`: Minimum allowed Julia version. - `develop::Bool=true`: Whether or not to `develop` new packages in the active environment. ### Git Options - `git::Bool=true`: Whether or not to create a Git repository for new packages. +- `host::AbstractString="github.com"`: URL to the code hosting service where packages will reside. - `ssh::Bool=false`: Whether or not to use SSH for the Git remote. If left unset, HTTPS will be used. - `manifest::Bool=false`: Whether or not to commit the `Manifest.toml`. @@ -44,6 +44,16 @@ A configuration used to generate packages. ### Interactive Usage - `interactive::Bool=false`: When set, the template is created interactively, filling unset keywords with user input. + +--- + +To create a package from a `Template`, use the following syntax: + +```julia +julia> t = Template(); + +julia> t("PkgName") +``` """ struct Template authors::Vector{String} diff --git a/test/plugin.jl b/test/plugin.jl index 05639f1e..c76efa07 100644 --- a/test/plugin.jl +++ b/test/plugin.jl @@ -21,6 +21,7 @@ PT.user_view(::BasicTest, ::Template, ::AbstractString) = Dict("X" => 1, "Z" => with_pkg(t) do pkg pkg_dir = joinpath(t.dir, pkg) badge = string(PT.Badge("1", "2", "3")) + @test occursin("a\naa\naaa", read(joinpath(pkg_dir, ".gitignore"), String)) @test occursin(badge, read(joinpath(pkg_dir, "README.md"), String)) @test read(joinpath(pkg_dir, "foo.txt"), String) == s end