PkgTemplates User Guide
Using PkgTemplates is straightforward. Just create a Template
, and call it on a package name to generate that package:
using PkgTemplates
t = Template()
t("MyPkg")
Template
PkgTemplates.Template
— TypeTemplate(; kwargs...)
A configuration used to generate packages.
Keyword Arguments
User Options
user::AbstractString="username"
: GitHub (or other code hosting service) username. The default value comes from the global Git config (github.user
). If no value is obtained, many plugins that use this value will not work.authors::Union{AbstractString, Vector{<:AbstractString}}="name <email> and contributors"
: Package authors. Likeuser
, it takes its default value from the global Git config (user.name
anduser.email
).
Package Options
dir::AbstractString="~/.julia/dev"
: Directory to place packages in.host::AbstractString="github.com"
: URL to the code hosting service where packages will reside.julia::VersionNumber=v"1.6.7"
: Minimum allowed Julia version.
Template Plugins
plugins::Vector{<:Plugin}=Plugin[]
: A list ofPlugin
s used by the template. The default plugins areProjectFile
,SrcDir
,Tests
,Readme
,License
,Git
,CompatHelper
,TagBot
andGitHubActions
. To disable a default plugin, pass in the negated type:!PluginType
. To override a default plugin instead of disabling it, pass in your own instance.
Interactive Mode
interactive::Bool=false
: In addition to specifying the template options with keywords, you can also build up a template by following a set of prompts. To create a template interactively, set this keyword totrue
. See also the similargenerate
function.
To create a package from a Template
, use the following syntax:
julia> t = Template();
julia> t("PkgName")
PkgTemplates.generate
— Functiongenerate([pkg::AbstractString]) -> Template
Shortcut for Template(; interactive=true)(pkg)
. If no package name is supplied, you will be prompted for one.
Plugins
Plugins add functionality to Template
s. There are a number of plugins available to automate common boilerplate tasks.
Default Plugins
These plugins are included by default. They can be overridden by supplying another value, or disabled by negating the type (!Type
), both as elements of the plugins
keyword.
PkgTemplates.ProjectFile
— TypeProjectFile(; version=v"1.0.0-DEV")
Creates a Project.toml
.
Keyword Arguments
version::VersionNumber
: The initial version of created packages.
PkgTemplates.SrcDir
— TypeSrcDir(; file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/src/module.jlt")
Creates a module entrypoint.
Keyword Arguments
file::AbstractString
: Template file forsrc/<module>.jl
.
PkgTemplates.Tests
— TypeTests(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/test/runtests.jlt",
project=false,
aqua=false,
aqua_kwargs=NamedTuple(),
jet=false,
)
Sets up testing for packages.
Keyword Arguments
file::AbstractString
: Template file forruntests.jl
.project::Bool
: Whether or not to create a new project for tests (test/Project.toml
). See the Pkg docs for more details.aqua::Bool
: Controls whether or not to add quality tests with Aqua.jl.aqua_kwargs::NamedTuple
: Which keyword arguments to supply to Aqua tests (many people useambiguities=false
for example)jet::Bool
: Controls whether or not to add a linting test with JET.jl (works best on type-stable code)
Managing test dependencies with test/Project.toml
is only supported in Julia 1.2 and later.
PkgTemplates.Readme
— TypeReadme(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/README.md",
destination="README.md",
inline_badges=false,
)
Creates a README
file that contains badges for other included plugins.
Keyword Arguments
file::AbstractString
: Template file for theREADME
.destination::AbstractString
: File destination, relative to the repository root. For example, values of"README"
or"README.rst"
might be desired.inline_badges::Bool
: Whether or not to put the badges on the same line as the package name.badge_order::Vector{typeof(Plugin)}
: Plugins in the order their badges should appear.badge_off::Vector{typeof(Plugin)}
: Plugins which should not have their badges added.
PkgTemplates.License
— TypeLicense(; name="MIT", path=nothing, destination="LICENSE")
Creates a license file.
Keyword Arguments
name::AbstractString
: Name of a license supported by PkgTemplates. Available licenses can be seen here.path::Union{AbstractString, Nothing}
: Path to a custom license file. This keyword takes priority overname
.destination::AbstractString
: File destination, relative to the repository root. For example,"LICENSE.md"
might be desired.
PkgTemplates.Git
— TypeGit(;
ignore=String[],
name=nothing,
email=nothing,
branch=LibGit2.getconfig("init.defaultBranch", "main")
ssh=false,
jl=true,
manifest=false,
gpgsign=false,
)
Creates a Git repository and a .gitignore
file.
Keyword Arguments
ignore::Vector{<:AbstractString}
: Patterns to add to the.gitignore
. See also:gitignore
.name::AbstractString
: Your real name, if you have not setuser.name
with Git.email::AbstractString
: Your email address, if you have not setuser.email
with Git.branch::AbstractString
: The desired name of the repository's default branch.ssh::Bool
: Whether or not to use SSH for the remote. If left unset, HTTPS is used.jl::Bool
: Whether or not to add a.jl
suffix to the remote URL.manifest::Bool
: Whether or not to commitManifest.toml
.gpgsign::Bool
: Whether or not to sign commits with your GPG key. This option requires that the Git CLI is installed, and for you to have a GPG key associated with your committer identity.
PkgTemplates.GitHubActions
— TypeGitHubActions(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/github/workflows/CI.yml",
destination="CI.yml",
linux=true,
osx=false,
windows=false,
x64=true,
x86=false,
coverage=true,
extra_versions=["1.6", "1.10", "pre"],
)
Integrates your packages with GitHub Actions.
Keyword Arguments
file::AbstractString
: Template file for the workflow file.destination::AbstractString
: Destination of the workflow file, relative to.github/workflows
.linux::Bool
: Whether or not to run builds on Linux.osx::Bool
: Whether or not to run builds on OSX (MacOS).windows::Bool
: Whether or not to run builds on Windows.x64::Bool
: Whether or not to run builds on 64-bit architecture.x86::Bool
: Whether or not to run builds on 32-bit architecture.coverage::Bool
: Whether or not to publish code coverage. Another code coverage plugin such asCodecov
must also be included.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
If using coverage plugins, don't forget to manually add your API tokens as secrets, as described here.
PkgTemplates.CompatHelper
— TypeCompatHelper(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/github/workflows/CompatHelper.yml",
destination="CompatHelper.yml",
cron="0 0 * * *",
)
Integrates your packages with CompatHelper via GitHub Actions.
Keyword Arguments
file::AbstractString
: Template file for the workflow file.destination::AbstractString
: Destination of the workflow file, relative to.github/workflows
.cron::AbstractString
: Cron expression for the schedule interval.
PkgTemplates.TagBot
— TypeTagBot(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/github/workflows/TagBot.yml",
destination="TagBot.yml",
trigger="JuliaTagBot",
token=Secret("GITHUB_TOKEN"),
ssh=Secret("DOCUMENTER_KEY"),
ssh_password=nothing,
changelog=nothing,
changelog_ignore=nothing,
gpg=nothing,
gpg_password=nothing,
registry=nothing,
branches=nothing,
dispatch=nothing,
dispatch_delay=nothing,
)
Adds GitHub release support via TagBot.
Keyword Arguments
file::AbstractString
: Template file for the workflow file.destination::AbstractString
: Destination of the workflow file, relative to.github/workflows
.trigger::AbstractString
: Username of the trigger user for custom registries.token::Secret
: Name of the token secret to use.ssh::Secret
: Name of the SSH private key secret to use.ssh_password::Secret
: Name of the SSH key password secret to use.changelog::AbstractString
: Custom changelog template.changelog_ignore::Vector{<:AbstractString}
: Issue/pull request labels to ignore in the changelog.gpg::Secret
: Name of the GPG private key secret to use.gpg_password::Secret
: Name of the GPG private key password secret to use.registry::AbstractString
: Custom registry, in the formatowner/repo
.branches::Bool
: Whether not to enable thebranches
option.dispatch::Bool
: Whether or not to enable thedispatch
option.dispatch_delay::Int
: Number of minutes to delay for dispatch events.
PkgTemplates.Secret
— TypeSecret(name::AbstractString)
Represents a GitHub repository secret. When converted to a string, yields ${{ secrets.<name> }}
.
PkgTemplates.Dependabot
— TypeDependabot(; file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/github/dependabot.yml")
Setups Dependabot to create PRs whenever GitHub actions can be updated. This is very similar to CompatHelper
, which performs the same task for Julia package dependencies.
Currently, this plugin is configured to setup Dependabot only for the GitHub actions package ecosystem. For example, it will create PRs whenever GitHub actions such as uses: actions/checkout@v3
can be updated to uses: actions/checkout@v4
. If you want to configure Dependabot to update other package ecosystems, please modify the resulting file yourself.
Keyword Arguments
file::AbstractString
: Template file fordependabot.yml
.
Continuous Integration (CI)
These plugins will create the configuration files of common CI services for you.
PkgTemplates.AppVeyor
— TypeAppVeyor(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/appveyor.yml",
x86=false,
coverage=true,
extra_versions=["1.6", "1.10", "nightly"],
)
Integrates your packages with AppVeyor via AppVeyor.jl.
Keyword Arguments
file::AbstractString
: Template file for.appveyor.yml
.x86::Bool
: Whether or not to run builds on 32-bit systems, in addition to the default 64-bit builds.coverage::Bool
: Whether or not to publish code coverage.Codecov
must also be included.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
PkgTemplates.CirrusCI
— TypeCirrusCI(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/cirrus.yml",
image="freebsd-12-0-release-amd64",
coverage=true,
extra_versions=["1.6", "1.10", "nightly"],
)
Integrates your packages with Cirrus CI via CirrusCI.jl.
Keyword Arguments
file::AbstractString
: Template file for.cirrus.yml
.image::AbstractString
: The FreeBSD image to be used.coverage::Bool
: Whether or not to publish code coverage.Codecov
must also be included.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
Code coverage submission from Cirrus CI is not yet supported by Coverage.jl.
PkgTemplates.DroneCI
— TypeDroneCI(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/drone.star",
amd64=true,
arm=false,
arm64=false,
extra_versions=["1.6", "1.10"],
)
Integrates your packages with Drone CI.
Keyword Arguments
file::AbstractString
: Template file for.drone.star
.destination::AbstractString
: File destination, relative to the repository root. For example, you might want to generate a.drone.yml
instead of the default Starlark file.amd64::Bool
: Whether or not to run builds on AMD64.arm::Bool
: Whether or not to run builds on ARM (32-bit).arm64::Bool
: Whether or not to run builds on ARM64.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
Nightly Julia is not supported.
PkgTemplates.GitLabCI
— TypeGitLabCI(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/gitlab-ci.yml",
coverage=true,
extra_versions=["1.6", "1.10"],
)
Integrates your packages with GitLab CI.
Keyword Arguments
file::AbstractString
: Template file for.gitlab-ci.yml
.coverage::Bool
: Whether or not to compute code coverage.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
GitLab Pages
Documentation can be generated by including a Documenter{GitLabCI}
plugin. See Documenter
for more information.
Nightly Julia is not supported.
PkgTemplates.TravisCI
— TypeTravisCI(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/travis.yml",
linux=true,
osx=false,
windows=false,
x64=true,
x86=false,
arm64=false,
coverage=true,
extra_versions=["1.6", "1.10", "nightly"],
)
Integrates your packages with Travis CI.
Keyword Arguments
file::AbstractString
: Template file for.travis.yml
.linux::Bool
: Whether or not to run builds on Linux.osx::Bool
: Whether or not to run builds on OSX (MacOS).windows::Bool
: Whether or not to run builds on Windows.x64::Bool
: Whether or not to run builds on 64-bit architecture.x86::Bool
: Whether or not to run builds on 32-bit architecture.arm64::Bool
: Whether or not to run builds on the ARM64 architecture.coverage::Bool
: Whether or not to publish code coverage. Another code coverage plugin such asCodecov
must also be included.extra_versions::Vector
: Extra Julia versions to test, as strings orVersionNumber
s.
Code Coverage
These plugins will enable code coverage reporting from CI.
PkgTemplates.Codecov
— TypeCodecov(; file=nothing)
Sets up code coverage submission from CI to Codecov.
Keyword Arguments
file::Union{AbstractString, Nothing}
: Template file for.codecov.yml
, ornothing
to create no file.
PkgTemplates.Coveralls
— TypeCoveralls(; file=nothing)
Sets up code coverage submission from CI to Coveralls.
Keyword Arguments
file::Union{AbstractString, Nothing}
: Template file for.coveralls.yml
, ornothing
to create no file.
Documentation
These plugins will help you build a documentation website.
PkgTemplates.Documenter
— TypeDocumenter{T}(;
make_jl="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/docs/make.jlt",
index_md="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/docs/src/index.md",
assets=String[],
logo=Logo(),
canonical_url=make_canonical(T),
devbranch=nothing,
edit_link=:devbranch,
makedocs_kwargs=Dict{Symbol,Any}(),
)
Sets up documentation generation via Documenter.jl. Documentation deployment depends on T
, where T
is some supported CI plugin, or Nothing
to only support local documentation builds.
If you are deploying documentation with GitHub Actions or Travis CI, don't forget to complete the required configuration. In particular, you may need to run
using DocumenterTools; DocumenterTools.genkeys(user="MyUser", repo="MyPackage.jl")
and follow the instructions there.
Supported Type Parameters
GitHubActions
: Deploys documentation to GitHub Pages with the help ofGitHubActions
.TravisCI
: Deploys documentation to GitHub Pages with the help ofTravisCI
.GitLabCI
: Deploys documentation to GitLab Pages with the help ofGitLabCI
.NoDeploy
(default): Does not set up documentation deployment.
Keyword Arguments
make_jl::AbstractString
: Template file formake.jl
.index_md::AbstractString
: Template file forindex.md
.assets::Vector{<:AbstractString}
: Extra assets for the generated site.logo::Logo
: ALogo
containing documentation logo information.canonical_url::Union{Function, Nothing}
: A function to generate the site's canonical URL. The default value will compute GitHub Pages and GitLab Pages URLs forTravisCI
andGitLabCI
, respectively. If set tonothing
, no canonical URL is set.edit_link::Union{AbstractString, Symbol, Nothing}
: Branch, tag or commit that the "Edit on…" link will point to. Defaults to the branch identified bydevbranch
. Ifedit_link=:commit
, then the link will point to the latest commit when docs are built. Ifedit_link=nothing
, then the "Edit on…" link will be hidden altogether.devbranch::Union{AbstractString, Nothing}
: Branch that will trigger docs deployment. Ifnothing
, then the default branch according to theTemplate
will be used.makedocs_kwargs::Dict{Symbol,Any}
: Extra keyword arguments to be inserted intomakedocs
.
PkgTemplates.Logo
— TypeLogo(; light=nothing, dark=nothing)
Logo information for documentation.
Keyword Arguments
light::AbstractString
: Path to a logo file for the light (default) theme.dark::AbstractString
: Path to a logo file for the dark theme.
Badges
These plugins will add badges to the README.
PkgTemplates.BlueStyleBadge
— TypePkgTemplates.ColPracBadge
— TypePkgTemplates.PkgEvalBadge
— TypePkgEvalBadge()
Adds a PkgEval
badge to the Readme
file.
Miscellaneous
PkgTemplates.Develop
— TypeDevelop()
Adds generated packages to the current environment by dev
ing them. See the Pkg documentation here for more details.
PkgTemplates.Citation
— TypeCitation(; file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/CITATION.bib", readme=false)
Creates a CITATION.bib
file for citing package repositories.
Keyword Arguments
file::AbstractString
: Template file forCITATION.bib
.readme::Bool
: Whether or not to include a section about citing in the README.
PkgTemplates.RegisterAction
— TypeRegisterAction(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/github/workflows/Register.yml",
destination="Register.yml",
prompt="Version to register or component to bump",
)
Add a GitHub Actions workflow for registering a package with the General registry via workflow dispatch. See here for more information.
Keyword Arguments
file::AbstractString
: Template file for the workflow file.destination::AbstractString
: Destination of the workflow file, relative to.github/workflows
.prompt::AbstractString
: Prompt for workflow dispatch.
PkgTemplates.Formatter
— TypeFormatter(;
file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/.JuliaFormatter.toml",
style="nostyle"
)
Create a .JuliaFormatter.toml
file, used by JuliaFormatter.jl and the Julia VSCode extension to configure automatic code formatting.
This file can be entirely customized by the user, see the JuliaFormatter.jl docs.
Keyword Arguments
file::String
: Template file for.JuliaFormatter.toml
.style::String
: Style name, defaults to"nostyle"
for an empty style but can also be one of("sciml", "blue", "yas")
for a fully preconfigured style.
PkgTemplates.CodeOwners
— TypeCodeOwners <: Plugin
CodeOwners(; owners)
A plugin which created GitLab/GitHub compatible CODEOWNERS files. owners should be a vector of patterns mapped to a vector of owner names. For example: owners=["*"=>["@invenia"], "README.md"=>["@documentation","@oxinabox]]
assigns general ownership over all files to the invenia group, but assigns ownership of the readme to the documentation group and to the user oxinabox.
By default, it creates an empty CODEOWNERS file.
PkgTemplates.PkgBenchmark
— TypePkgBenchmark(; file="~/work/PkgTemplates.jl/PkgTemplates.jl/templates/benchmark/benchmarks.jlt")
Sets up a PkgBenchmark.jl benchmark suite.
To ensure benchmark reproducibility, you will need to manually create an environment in the benchmark
subfolder (for which the Manifest.toml
is committed to version control). In this environment, you should at the very least:
pkg> add BenchmarkTools
pkg> dev
your new package.
Keyword Arguments
file::AbstractString
: Template file forbenchmarks.jl
.
A More Complicated Example
Here are a few example templates that use the options and plugins explained above.
This one includes plugins suitable for a project hosted on GitHub, and some other customizations:
Template(;
user="my-username",
dir="~/code",
authors="Acme Corp",
julia=v"1.1",
plugins=[
License(; name="MPL"),
Git(; manifest=true, ssh=true),
GitHubActions(; x86=true),
Codecov(),
Documenter{GitHubActions}(),
Develop(),
],
)
Here's one that works well for projects hosted on GitLab:
Template(;
user="my-username",
host="gitlab.com",
plugins=[
GitLabCI(),
Documenter{GitLabCI}(),
],
)
Custom Template Files
This documentation refers plenty to Template
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 or Mustache (Mustache is the particular flavour used by PkgTemplates, via Mustache.jl). Please keep the difference between these two things in mind!
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'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.
You might notice that some curlies are in groups of two ({{key}}
), and some are in groups of three ({{{key}}}
). Whenever we want to subtitute in a value, using the triple curlies disables HTML escaping, which we rarely want for the types of files we're creating. If you do want escaping, just use the double curlies. And if you're using different delimiters, for example <<foo>>
, use <<&foo>>
to disable escaping.
Assuming the following view:
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
to supply whatever data is necessary for your use case.
PkgTemplates.user_view
— Functionuser_view(::Plugin, ::Template, pkg::AbstractString) -> Dict{String, Any}
The same as view
, but for use by package users for extension.
Values returned by this function will override those from view
when the keys are the same.
For example, suppose you were using the Readme
plugin with a custom template file that looked like this:
# {{PKG}}
Created on *{{TODAY}}*.
The view
function supplies a value for PKG
, but it does not supply a value for TODAY
. Rather than override view
, we can implement this function to get both the default values and whatever else we need to add.
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. This means using the same template more than once, so we want a way to save a template to be used later.
Here's my recommendation for loading a template whenever it's needed:
function template()
@eval begin
using PkgTemplates
Template(; #= ... =#)
end
end
Add this to your startup.jl
, and you can create your template from anywhere, without incurring any startup cost.
Another strategy is to write the string representation of the template to a Julia file:
const t = Template(; #= ... =#)
open("template.jl", "w") do io
println(io, "using PkgTemplates")
print(io, t)
end
Then the template is just an include
away:
const t = include("template.jl")
The only disadvantage to this approach is that the saved template is much less human-readable than code you wrote yourself.
One more method of saving templates is to simply use the Serialization package in the standard library:
const t = Template(; #= ... =#)
using Serialization
open(io -> serialize(io, t), "template.bin", "w")
Then simply deserialize
to load:
using Serialization
const t = open(deserialize, "template.bin")
This approach has the same disadvantage as the previous one, and the serialization format is not guaranteed to be stable across Julia versions.