<!--
SPDX-FileCopyrightText: © 2025 open-nudge <https://github.com/open-nudge>
SPDX-FileContributor: szymonmaszke <github@maszke.co>

SPDX-License-Identifier: Apache-2.0
-->

# opentemplate

<!-- mkdocs remove start -->

<!-- vale off -->

<!-- pyml disable-num-lines 30 line-length-->

<p align="center">
    <em>All-in-one Python template. One click. Everything included.</em>
</p>

<div align="center">

<a href="https://pypi.org/project/opentemplate">![PyPI - Python Version](https://img.shields.io/pypi/v/opentemplate?style=for-the-badge&label=release&labelColor=grey&color=blue)
</a>
<a href="https://pypi.org/project/opentemplate">![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fopen-nudge%2Fopentemplate%2Fmain%2Fpyproject.toml&style=for-the-badge&label=python&labelColor=grey&color=blue)
</a>
<a href="https://opensource.org/licenses/Apache-2.0">![License](https://img.shields.io/badge/License-Apache_2.0-blue?style=for-the-badge)
</a>
<a>![Coverage Hardcoded](https://img.shields.io/badge/coverage-100%25-green?style=for-the-badge)
</a>
<a href="https://scorecard.dev/viewer/?uri=github.com/open-nudge/opentemplate">![OSSF-Scorecard Score](https://img.shields.io/ossf-scorecard/github.com/open-nudge/opentemplate?style=for-the-badge&label=OSSF)
</a>

</div>

<p align="center">
✨ <a href="#features">Features</a>
🚀 <a href="#quick-start">Quick start</a>
📚 <a href="https://open-nudge.github.io/opentemplate">Documentation</a>
🤝 <a href="#contribute">Contribute</a>
👍 <a href="https://github.com/open-nudge/opentemplate/blob/main/ADOPTERS.md">Adopters</a>
📜 <a href="#legal">Legal</a>
</p>

______________________________________________________________________

<!-- mkdocs remove end -->

## Features

__opentemplate__ is a Python template which is:

- [__Truly open source__](https://open-nudge.github.io/opentemplate/template/about/philosophy):
    no tokens, no fees, no premium plans, open source software only
- [__Easy to use__](https://open-nudge.github.io/opentemplate/template/quickstart/usage):
    clone templated repo, run `pdm setup` and __focus on your code__
- [__State of the art__](https://open-nudge.github.io/opentemplate/template/details):
    best checkers for Python, YAML, Markdown, prose, and more unified
- [__Secure__](https://open-nudge.github.io/opentemplate/template/details/security):
    [SLSA Level 3](https://slsa.dev/spec/v1.0-rc1/levels), [SBOMs](https://www.cisa.gov/sbom),
    [attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds),
    [secured egress](https://github.com/step-security/harden-runner),
    [OSSF Best Practices](https://github.com/ossf/scorecard)
- [__Consistent__](https://open-nudge.github.io/opentemplate/template/configuration/basic):
    all pipelines (`GitHub Actions`, `pre-commit`)
    share the same `pyproject.toml` config
- [__Performant__](https://open-nudge.github.io/opentemplate/template/details/github-actions):
    parallel checks, builds, minimally-sized caches and checkouts

> [!IMPORTANT]
> __An example repository using `opentemplate`
> [here](https://github.com/open-nudge/cogeol)__

> [!CAUTION]
> __All files in this repo will be copied to your project,
> using the title and description you provide.__

<!-- vale on -->

### Code quality (Python focused)

> [!IMPORTANT]
> __You can adjust everything from `pyproject.toml` level!__

- __Package manager:__ [`pdm`](https://pdm-project.org/en/latest/)
    with a single `pdm setup` manages everything!
    (see [why pdm](https://open-nudge.github.io/opentemplate/latest/template/about/faq/#why-use-pdm-instead-of-uv))
- __Testing:__ [`pytest`](https://docs.pytest.org/en/stable/)
    (with [`coverage`](https://coverage.readthedocs.io/en/7.9.1/),
    and [`hypothesis`](https://hypothesis.readthedocs.io/en/latest/) for
    fuzzing); __testing across all Python versions
    done WITHOUT [`tox`](https://tox.wiki/en/4.27.0/)
    or [`nox`](https://nox.thea.codes/en/stable/)__(managed directly by `pdm`!)
- __Documentation:__ [`mkdocs`](https://www.mkdocs.org/) -
    __document once, have it everywhere (unified look on GitHub and hosted docs)__,
    [semantically versioned](https://semver.org/)
    (via [`mike`](https://github.com/jimporter/mike)),
    autogenerated from
    [coverage](https://github.com/econchick/interrogate),
    [deadlink](https://github.com/AlexanderDokuchaev/md-dead-link-check)
    and [spell-checked](https://github.com/codespell-project/codespell) docstrings,
    automatically deployed after each GitHub release with clean
    [material design look](https://github.com/squidfunk/mkdocs-material)
- __Code formatting and linting:__ [`ruff`](https://github.com/astral-sh/ruff)
    (checks hand-picked for best quality and ease of use; most are enabled),
    [`basedpyright`](https://github.com/DetachHead/basedpyright)
    for type checking, [`FawltyDeps`](https://github.com/tweag/FawltyDeps)
    for static dependency analysis
- __Each file is copyrighted with your git information__ -
    copyrights added automatically by `pre-commit`,
    see [REUSE](https://reuse.readthedocs.io/en/stable/) and
    [SPDX Licensing](https://spdx.dev/learn/handling-license-info/)
    for more information
- __Automated Python version updates__: `pyproject.toml`
    (and GitHub Actions pipelines where necessary)
    are automatically updated to always use __3 latest Python
    versions__ (via [`cogeol`](https://pypi.org/project/cogeol/))
    according to [Scientific Python SPEC0](https://scientific-python.org/specs/spec-0000/)
    deprecation and end-of-life policies
- __Other code linting__: checks for `YAML`, `Markdown`, `INI`, `JSON`, `prose`,
    all config files, `shell`, `GitHub Actions` -
    __all grouped as `check-<group>` and `fix-<group>` `pdm` commands__
- __Release to `PyPI` and `GitHub`__: done by making a
    [GitHub release](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases),
    each release is attested and immutably versioned via
    [`commition`](https://pypi.org/project/commition/)
- [__`pre-commit`__](https://pre-commit.com/): __all checks and fixers are run
    before commit__, no need to remember them!
    (`pre-commit` is also setup after running a single `pdm setup` command!)

### Security

> [!IMPORTANT]
> __Everything below is already provided out of the box, one-click only!__

- [__Hardening__](https://open-nudge.github.io/opentemplate/latest/template/quickstart/installation/#hardening):
    during setup, an automated issue is created to guide you step by step
    through enabling rulesets, branch protection, mandatory reviewers,
    necessary signatures etc.
    ([see here for an example](https://github.com/open-nudge/opentemplate/issues/1)).
    Best part? __`harden.yml` workflow, which does that
    automatically__ (if you follow the instructions in the issue)!
- [__SLSA compliance__](https://slsa.dev/spec/v1.0-rc1/levels):
    Level 3+ for public/enterprise repositories
    and L2 for private repositories
    via [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator)
- __[Software Bills of Materials](https://www.cisa.gov/sbom) (SBOMs)__:
    generated per-Python, per-OS, per-dependency group -
    __each [attested](https://github.com/actions/attest)__,
    and attached to the release
- __Static security analysis tooling__: [`osv-scanner`](https://github.com/google/osv-scanner)
    checks against [OSV database](https://osv.dev/),
    [`semgrep`](https://semgrep.dev/) monitors code quality and security,
    [`zizmor`](https://github.com/zizmorcore/zizmor) verifies workflows,
    while [`trufflehog`](https://github.com/trufflesecurity/trufflehog)
    looks for leaked secrets
- __Reusable workflows__: most of the workflows are [reusable](https://docs.github.com/en/actions/sharing-automations/reusing-workflows)
    (pointing to `opentemplate` workflows) to improve security and
    __get automated pipeline updates__ - you can make them local by
    running `.github/reusability/localize.sh` script. __No need
    to manage/update your own workflows!__
- __Pinned dependencies__: all dependencies are pinned to specific versions
    (GitHub Actions, `pre-commit` and `pdm.lock`)
- __Monitored egress in GitHub Actions__: [`harden-runner`](https://github.com/step-security/harden-runner)
    with a __whitelisted minimal set of domains__ necessary to run the workflows
- __Security documentation__: `SECURITY.md`, `SECURITY-INSIGHTS.yml`,
    `SECURITY-SELF-ASSESSMENT.md` (only security file to update
    manually before release), and `SECURITY-DEPENDENCY.md`
    define high quality security policies

> [!TIP]
> See [this example release](https://github.com/open-nudge/opentemplate/releases/tag/v0.1.3)
> for all security artifacts described above.

> [!NOTE]
> Although there is __around 100__ workflows helping you
> maintain high quality, __most of them reuse the same workflow__,
> which makes them maintainable and extendable.

### GitHub

- __GitHub Actions cache__ - after each merge
    to the `main` branch, dependencies are cached __per-group and
    per-OS__ for maximum performance
- __Minimal checkouts and triggers__ - each workflow is
    __triggered based on appropriate path__ and performs
    [`sparse-checkout`](https://github.blog/open-source/git/bring-your-monorepo-down-to-size-with-sparse-checkout/)
    when possible to minimize the amount of data transferred;
    __great for large repositories with many files and large history__
- __Dependency updates__: [Renovate](https://docs.renovatebot.com/)
    updates all dependencies in a grouped manner once a week
- __Templates__: __every possible template included__ (discussions,
    issues, pull requests - each extensively described)
- __Predefined labels__ - each pull request will be automatically labeled
    (over `20` labels created during setup!) based on changed files
    (e.g. `docs`, `tests`, `deps`, `config` etc.).
    __No need to specify [semver](https://semver.org/) `scope`
    of commit anymore!__
- __Open source documents__: `CODE_OF_CONDUCT.md`,
    `CONTRIBUTING.md`, `ROADMAP.md`, `CHANGELOG.md`, `CODEOWNERS`, `DCO`,
    and much more - all automatically added and linked to your
    Python documentation out of the box
- __Release changelog__: [`git-cliff`](https://git-cliff.org/) - commits
    automatically divided based on `labels`, `types`, human/bot authors,
    and linked to appropriate issues and pull requests
- __Config files__: [editorconfig](https://editorconfig.org/), `.gitattributes`,
    always the latest Python `.gitignore` etc.
- __Commit checks__: verification of signatures, commit messages,
    DCO signing, no commit to the main branch policy
    (via [conform](https://github.com/siderolabs/conform))

## Comparison

- Broader scope than other [`cookiecutter`](https://github.com/cookiecutter/cookiecutter)
    templates (e.g. one-click and one-command setup, security,
    GitHub Actions, comprehensive docs, rulesets. deprecation policies,
    automated copyrights and more).
    Check [here](https://github.com/fpgmaas/cookiecutter-uv)
    or [here](https://github.com/audreyfeldroy/cookiecutter-pypackage)
    to compare yourself.
- Truly FOSS (no freemium, no paid plans, no tokens) when compared to commercial
    offerings like [`snyk`](https://snyk.io/) or
    [`jit.io`](https://www.jit.io/). Additionally Python-centric and sticks
    with tools widely known by developers (their own environment and
    GitHub interface).

> [!TIP]
> See detailed comparison in the
> [documentation](https://open-nudge.github.io/opentemplate/latest/template/about/comparison/)

## Quick start

### Installation

> [!NOTE]
> [Install `pdm`](https://pdm-project.org/en/latest/#recommended-installation-method)
> (if you don't have it already), for Linux/MacOS:

```sh
curl -sSL https://pdm-project.org/install-pdm.py | python3 -
```

1. Create a new GitHub repository using this template
    (green `Use this template` button)
1. Name your repo (__use underscore `_`, not hyphens `-`__)
1. Add project description (__necessary!__)
1. __Wait until the setup commit appears__
    (performed by `github-actions[bot]`, it may take a few minutes)
1. Clone the repository
1. Run `pdm setup` command locally to setup development environment

> [!TIP]
> For more details read the
> [documentation](https://open-nudge.github.io/opentemplate/template/quickstart/installation)

### Usage

1. Create a new branch
1. Optionally add dependencies to `pyproject.toml`
1. Write code in `/src/<project_name>` and tests in `/tests`
1. Use `git add`, `git commit` and `git push` your changes
1. `pre-commit` will guide you through the process

> [!TIP]
> For more details read the
> [documentation](https://open-nudge.github.io/opentemplate/template/quickstart/usage)

### Examples

> [!CAUTION]
> Click on each example to see it in action!

<details>
  <summary><b><big>Run checkers or fixers manually</big></b> (click me)</summary>
&nbsp;

```sh
> pdm check-<group> [FILE1, FILE2, ...] # pdm fix-<group>
```

For example, to check __all Python files__:

```sh
> pdm check-python
```

Or to check `/src/__init__.py`:

```sh
> pdm check-python src/__init__.py
```

Note that all `check` and `fix` commands are grouped for your convenience:

```sh
> pdm check-all # pdm fix-all
```

</details>

<details>
  <summary><b><big>Adjust template</big></b> (click me)</summary>
&nbsp;

> Most of the adjustments can be done by __only__ editing `pyproject.toml`

Common changes to `pyproject.toml`:

- Add dev dependencies under `[dependency-groups]`
    (everything is named `dev-<group>`)
- Modify `[tool.pdm.scripts]` for custom command
    (`check-<group>` or `fix-<group>`, the latter modifies files)
- Use `[tool.<name>]` to adjust specific tool configuration

> __Adjusting these sections will affect `pre-commit` and `GitHub Actions`__

</details>

<details>
  <summary><b><big>Disable some pre-commit check</big></b> (click me)</summary>
&nbsp;

> Disabling checks should be done cautiously!

`pre-commit` checks are defined in `.pre-commit-config.yaml`.

Disable a check using `SKIP` environment variable:

```sh
SKIP="<group1>,<group2>" git commit -m <message>
```

For example, the following will skip `DCO` and `ini` checks
and Python fixes (which would modify files):

```sh
SKIP="dco,ini,fix-python" git commit -m <message>
```

For details, refer to the `id` fields in `.pre-commit-config.yaml`.

> Some commands have both `<group>-fix` and `<group>-check`
> for different actions!

</details>

<details>
  <summary><b><big>Disable GitHub Actions checks</big></b> (click me)</summary>
&nbsp;

> Disabling checks should be done cautiously!

When making a commit you can add one of the following
strings to the message:

- `[skip ci]`
- `[ci skip]`
- `[no ci]`
- `[skip actions]`
- `[actions skip]`

> Note that you can also merge pull requests __even if the checks fail__.

</details>

<!-- mkdocs remove start -->

## Contribute

We welcome your contributions! Start here:

- [Code of Conduct](/CODE_OF_CONDUCT.md)
- [Contributing Guide](/CONTRIBUTING.md)
- [Roadmap](/ROADMAP.md)
- [Changelog](/CHANGELOG.md)
- [Report security vulnerabilities](/SECURITY.md)
- [Open an Issue](https://github.com/open-nudge/opentemplate/issues)

## Legal

- This project is licensed under the _Apache 2.0 License_ - see
    the [LICENSE](/LICENSE.md) file for details.
- This project is copyrighted by _open-nudge_ - the
    appropriate copyright notice is included in each file.

<!-- mkdocs remove end -->

<!-- md-dead-link-check: on -->
