The Velexi Julia Package Cookiecutter is intended to streamline the process of setting up a Julia package that
-
encourages the creation of high-quality software,
-
promotes developer efficiency, and
-
is distribution-ready.
-
Standard Julia package structure (e.g., based on PkgTemplates)
-
Automated testing and coverage reporting framework (e.g., jltest, jlcoverage)
-
Integration with code quality tools (e.g., pre-commit, jlcodestyle)
-
Continuous integration (CI) via GitHub Actions (e.g., testing, documentation deployment)
-
References for Julia package development
-
Directory-based development environment isolation with direnv
-
2.1. License
2.2. Repository Contents
2.4. Setting Up to Develop the Cookiecutter
2.5. Additional Notes
-
package_name
: package name -
author
: package's primary author -
email
: primary author's email -
license
: type of license to use for the package -
julia_version
: Julia versions compatible with the package. See the "Version specifier format" section of the official Julia documentation for version specifier semantics. -
github_repo_owner
: owner of the GitHub repository for the package -
enable_github_pages
: flag indicating whether GitHub Pages should be enabled for the package -
ci_include_codecov
: flag indicating whether the CI workflow should upload coverage statistics to Codecov -
ci_include_x86
: flag indicating whether the CI testing matrix should include the x86 architecture -
tagbot_use_gpg_signing
: flag indicating whether TagBot should sign the tags it creates
-
Prerequisites
-
Install Git.
-
Install Julia 1.7 (or greater).
-
Install Python 3.9 (or greater).
Note. Python is only required for a few purposes:
-
by Cookiecutter at setup time and
-
by the Git pre-commit hooks during development.
-
-
Install Poetry 1.2 (or greater).
-
Install the Cookiecutter Python package.
-
Install the TestTools Julia package.
-
Optional. Install direnv.
-
-
Use
cookiecutter
to create a new Julia package.$ cookiecutter https://github.com/velexi-research/VLXI-Cookiecutter-Julia.git
-
Set up the Python development tools for the package.
-
Set up a dedicated virtual environment for the package. Any of the common virtual environment options (e.g.,
venv
,direnv
,conda
) should work. Below are instructions for setting up adirenv
orpoetry
environment.Note: to avoid conflicts between virtual environments, only one method should be used to manage the virtual environment.
-
direnv
Environment. Note:direnv
manages the environment for both Python and the shell.-
Prerequisite. Install
direnv
. -
Copy
extras/dot-envrc
to the package root directory, and rename it to.envrc
.$ cd $PROJECT_ROOT_DIR $ cp extras/dot-envrc .envrc
-
Grant permission to direnv to execute the .envrc file.
$ direnv allow
-
-
poetry
Environment. Note:poetry
only manages the Python environment (it does not manage the shell environment).-
Create a
poetry
environment that uses a specific Python executable. For instance, ifpython3
is on yourPATH
, the following command creates (or activates if it already exists) a Python virtual environment that usespython3
.$ poetry env use python3
For commands to use other Python executables for the virtual environment, see the Poetry Quick Reference.
-
-
-
Install the Python package dependencies and update them to the latest available versions.
$ poetry install $ poetry update
-
Commit the updated
poetry.lock
files to the package Git repository.
-
-
Configure Git.
-
Install the Git pre-commit hooks.
$ pre-commit install
-
Optional. Set up a remote Git repository (e.g., GitHub repository).
-
Create a remote Git repository.
-
Configure the remote Git repository.
$ git remote add origin GIT_REMOTE
where
GIT_REMOTE
is the URL of the remote Git repository. -
Push the
main
branch to the remote Git repository.$ git checkout main $ git push -u origin main
-
If GitHub Pages are enabled for the package, push the
gh-pages
branch to the remote Git repository.$ git checkout gh-pages $ git push -u origin gh-pages
-
-
-
Finish setting up the new Julia package.
-
Verify the copyright year and owner in the copyright notice. If the package is licensed under Apache License 2.0, the copyright notice is located in the
NOTICE
file. Otherwise, the copyright notice is located in theLICENSE
file. -
Verify the URLs in
docs/make.jl
, the Julia documentation build script.-
makedocs()
-
repo
. If present, remove therepo
argument.repo
has been replaced by therepolink
argument toDocumenter.HTML()
(see below). -
Documenter.HTML()
-
Check the URL for the
canonical
argument. Note: the URL should contain the protocol (e.g.,https://
).Example:
https://user.github.io/Package.jl
-
Add the
repolink
argument. Make sure that the URL contains the protocol (e.g.,https://
).Example:
https://github.com/user/Package.jl
-
-
warnonly
(Optional). Allow docstrings to be excluded from the package documentationExample:
warnonly=[:missing_docs]
-
-
deploydocs()
. Check the URL for therepo
argument. Note: the URL should not contain the protocol (e.g.,https://
).Example:
github.com/user/Package.jl
-
-
Fill in any empty fields in
pyproject.toml
. -
Customize the
README.md
file to reflect the specifics of the package. -
Commit all updated files (e.g.,
poetry.lock
) to the package Git repository.
-
-
Add GitHub keys that are required for GitHub Actions workflows.
Documentation Deployment
-
Use the Julia
DocumenterTools
package to generate a key pair (with private key Base64-encoded).julia> using DocumenterTools julia> DocumenterTools.genkeys()
-
Add the public key as a GitHub Deploy key.
-
From the package GitHub repository, navigate to "Settings" > "Deploy keys" (in the "Security" section of the side menu).
-
Enable "Allow write access"
-
-
Add the private key as a GitHub Secret for GitHub Actions.
From the package GitHub repository, navigate to "Settings" > "Secrets and variables"
"Actions" (in the "Security" section of the side menu).
Add a repository secret named
DOCUMENTER_KEY
.
Codecov Token
These steps are needed only if the CI workflow includes uploading of coverage statistics to Codecov (i.e.,
ci_include_codecov
set toyes
when creating the package).-
Log into Codecov and enable the package GitHub repository on Codecov.
-
Get the Codecov token for the repository by navigating to "Settings" from the package Codecov repo page.
-
From the package GitHub repository, navigate to "Settings" > "Secrets and variables"
"Actions" (in the "Security" section of the side menu).
-
Add a repository secret named
CODECOV_TOKEN
.
GPG Signing
These steps are needed only if TagBot is configured to use GPG signing (i.e.,
tagbot_use_gpg_signing
set toyes
when creating the package).-
Generate and export a GPG key pair.
$ # Generate GPG key $ gpg --full-generate-key $ # Export public key in ASCII armor format (Base64-encoded) $ gpg --armor --export KEY_ID $ # Export private key in ASCII armor format (Base64-encoded) $ gpg --armor --export-secret-keys KEY_ID
-
From the package GitHub repository, navigate to "Settings" > "Secrets" (in the "Security" section of the side menu).
-
Add repository secrets with the following names.
GPG_KEY
: public keyGPG_PASSWORD
: private key
-
-
Recommended. Customize the settings for the package GitHub repository.
Code Stability. Branch protection helps ensure that there is always a relatively stable code branch.
-
From the package GitHub repository, navigate to "Settings" > "General". Set the default branch to
main
. -
From the package GitHub repository, navigate to "Settings" > "Branches" (in the "Code and automation" section of the side menu).
-
Add branch protection for the
main
branch and enable the following configurations.-
Require a pull request before merging
-
Require approvals
-
Recommendation: enable for projects with multiple active developers who can serve as reviewers
-
Warning: must be disabled for projects with a single developer
-
-
-
Require conversation resolution before merging
-
Do not allow bypassing the above settings
-
GitHub Actions Security. Restricting GitHub Actions decreases the chances of accidental (or intentional) modifications to the code base.
-
From the package GitHub repository, navigate to "Settings" > "Actions" > "General" (in the "Code and automation" section of the side menu).
-
Configure "Actions permissions".
-
Select the most restrictive option and customize the sub-options.
-
Allow actions created by GitHub: yes
-
Allow actions by Marketplace verified creators: no
-
Allow specified actions and reusable workflows.
codecov/codecov-action@*, dcarbone/install-jq-action@*, julia-actions/*, JuliaRegistries/TagBot@*, pytooling/*,
Note. "Allow specified actions and reusable workflows" settings only apply to public repositories. Private repositories that rely on actions and workflows listed in the "Allow specified actions and reusable workflows" settings will fail.
-
-
-
Configure "Workflow permissions".
-
Select "Read repository content permissions".
-
Allow GitHub Actions to create and approve pull requests: yes
-
-
-
From the package GitHub repository, navigate to "Settings" > "Pages" (in the "Code and automation" section of the side menu) and configure GitHub Pages to use "gh-pages/(root)" as its "Source".
- Source: Deploy from a branch
- Branch:
gh-pages/(root)
-
In the "About" section of the package GitHub repository, set "Website" to the URL for the package GitHub Pages.
-
That's it! Every time the
main
branch is updated, the CI and gh-pages workflows will automatically update the package documentation on GitHub Pages.
The contents of this cookiecutter are covered under the Apache License 2.0 (included in the
LICENSE
file). The copyright for this cookiecutter is contained in the NOTICE
file.
├── README.md <- this file
├── NEWS.md <- cookiecutter release notes
├── LICENSE <- cookiecutter license
├── NOTICE <- cookiecutter copyright notice
├── cookiecutter.json <- cookiecutter configuration file
├── pyproject.toml <- Python metadata file for cookiecutter development
├── poetry.lock <- Poetry lockfile
├── docs/ <- cookiecutter documentation
├── extras/ <- additional files that may be useful for
│ cookiecutter development
├── hooks/ <- cookiecutter scripts that run before and/or
│ after package generation
├── spikes/ <- experimental code
└── {{cookiecutter.name}}/ <- cookiecutter template
See [tool.poetry.dependencies]
section of pyproject.toml
.
-
Set up a dedicated virtual environment for cookiecutter development. See Step 3 from Section 2.1 for instructions on how to set up
direnv
andpoetry
environments. -
Install the Python packages required for development.
$ poetry install
-
Install the Git pre-commit hooks.
$ pre-commit install
-
Make the cookiecutter better!
To update the Python dependencies for the template (contained in the
{{cookiecutter.__package_name}}
directory), use the following procedure to
ensure that Python package dependencies for developing the non-template
components of the cookiecutter (e.g., cookiecutter hooks) do not interfere with
Python package dependencies for the template.
-
Create a local clone of the cookiecutter Git repository to use for cookiecutter development.
$ git clone [email protected]:velexi-research/VLXI-Cookiecutter-Julia.git
-
Use
cookiecutter
from the local cookiecutter Git repository to create an instance of the template to use for updating Python package dependencies.$ cookiecutter PATH/TO/LOCAL/REPO
-
In the instance of the template, perform the following steps to update the template's Python package dependencies.
-
Set up a virtual environment for developing the template (e.g., a direnv environment).
-
Use
poetry
or manually editpyproject.toml
to (1) make changes to the Python package dependency list and (2) update the versions of Python package dependencies. -
Use
poetry
to update the Python package dependencies and versions recorded in thepoetry.lock
file.
-
-
Update
{{cookiecutter.__package_name}}/pyproject.toml
.-
Copy
pyproject.toml
from the instance of the template to{{cookiecutter.__package_name}}/pyproject.toml
. -
Restore the templated values in the
[tool.poetry]
section to the following:[tool.poetry] name = "{{ cookiecutter.__package_name }}" version = "0.1.0" description = "" license = "{% if cookiecutter.license == 'ASL' %}Apache-2.0{% elif cookiecutter.license == 'BSD3' %}BSD-3-Clause{% elif cookiecutter.license == 'MIT' %}MIT{% endif %}" readme = "README.md" authors = ["{{ cookiecutter.author }} <{{ cookiecutter.email }}>"]
-
-
Update
{{cookiecutter.__package_name}}/poetry.lock
.- Copy
poetry.lock
from the instance of the template to{{cookiecutter.__package_name}}/poetry.lock
.
- Copy
-
Commit the updated
pyproject.toml
andpoetry.lock
files to the Git repository.