Skip to content

Commit

Permalink
Updates for January 2024 (#30)
Browse files Browse the repository at this point in the history
### Changes

* Updated `bump-my-version` to use a
[SemVer-v2.0](https://semver.org/spec/v2.0.0.html)-compliant versioning
scheme.
* Updated much of the information in the top-level `README` file to
explain some of the post-install processes required. More documentation
is probably necessary.
* Organized both the top-level and recipe-level `README`'s for easier
updating and clarity.
* Added some security steps to existing GitHub Workflows.
* Added a configuration for
[Dependabot](https://docs.github.com/en/code-security/dependabot/working-with-dependabot)
(replaces `actions-version-updater.yml`).
* Added workflows for automatic labelling, for [OpenSSF
Scorecard](https://securityscorecards.dev/), for automated cleaning of
GitHub Cache, and for Dependency-related security issues.
* Added a workflow (`workflow-warning.yml`) for emitting warnings for
reviewers when an external service/user updates workflow files.
* Updated `pre-commit` hook versions.
* Updated project metadata to specify that `Python3.12` is supported.
  • Loading branch information
Zeitsperre authored Jan 29, 2024
2 parents 6dd92dd + fae9f21 commit f091c34
Show file tree
Hide file tree
Showing 23 changed files with 616 additions and 132 deletions.
8 changes: 8 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### What kind of change does this PR introduce?

* ...

### Does this PR introduce a breaking change?


### Other information:
145 changes: 97 additions & 48 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,12 @@
Cookiecutter PyPackage
======================

.. image:: https://pyup.io/repos/github/audreyfeldroy/cookiecutter-pypackage/shield.svg
:target: https://pyup.io/repos/github/audreyfeldroy/cookiecutter-pypackage/
:alt: Updates

.. image:: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml/badge.svg
:target: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml
:alt: Build Status

.. image:: https://readthedocs.org/projects/cookiecutter-pypackage/badge/?version=latest
:target: https://cookiecutter-pypackage.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
|build|

Cookiecutter_ template for a Python package.

* GitHub repo (fork): https://github.com/Ouranosinc/cookiecutter-pypackage/
* Documentation: https://cookiecutter-pypackage.readthedocs.io/
* Documentation (upstream): https://cookiecutter-pypackage.readthedocs.io/
* Free software: BSD license

Features
Expand All @@ -29,51 +19,93 @@ Features
* `Conda`_ environment file: Optionally use ``conda env create -f environment-dev.yml`` to create a new environment with the correct Python version.
* Tox_ testing: Setup to easily test for Python 3.8, 3.9, 3.10, 3.11, 3.12, and PyPy3.
* Sphinx_ docs: Documentation ready for generation with, for example, `Read the Docs`_
* pre-commit_ hook: Run your tests and linting (e.g. Flake8, Black) before you commit your code!
* bump-my-version_: Pre-configured version bumping with a single command
* pre-commit_ hook: Run your tests and linting (e.g. `black`, `flake8`, `pylint`, etc.) before you commit your code!
* `pre-commit.ci`_: Automate `pre-commit` checks and corrections in your Pull Requests.
* bump-my-version_: Pre-configured `SemVer-2.0-compliant`_ version bumping with a single command.
* dependabot_ for automated dependency updates of both project dependencies and GitHub Actions.
* `sphinx-intl`_ for French internationalization (i18n) and localization (l10n) of Sphinx docs (optional)
* Auto-release to PyPI_ when you push a new tag to main (optional)
* Auto-release to TestPyPI_ and PyPI_ when you push a new tag to main (optional)
* Command line interface using Click (optional)

Build Status
-------------

Linux:

.. image:: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml/badge.svg
:target: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml
:alt: Linux build status on GitHub Actions
Upstream (audreyfeldroy/cookiecutter-pypackage): |docs-upstream| |pyup-upstream|

Quickstart
----------

Install the latest Cookiecutter if you haven't installed it yet (this requires
Cookiecutter 1.4.0 or higher)::
Install the latest Cookiecutter if you haven't installed it yet ::

$ pip install -U cookiecutter

Or, if using Conda::

$ conda install -c conda-forge cookiecutter

Generate a Python package project::

$ cookiecutter https://github.com/Ouranosinc/cookiecutter-pypackage.git

Then:

* Create a repo and put it there.
* Install the dev requirements into a virtualenv. (``pip install -r requirements_dev.txt``)
* Register_ your project with PyPI.
* Enable GitHub Actions and Workflows and activate automated deployment on PyPI when you push a new tag to main branch.
* Add the repo to your `Read the Docs`_ account + turn on the Read the Docs service hook.
* Release your package by pushing a new tag to main.
* Add a ``requirements.txt`` file that specifies the packages you will need for
your project and their versions. For more info see the `pip docs for requirements files`_.
* Activate your project on `pyup.io`_.

.. _`pip docs for requirements files`: https://pip.pypa.io/en/stable/user_guide/#requirements-files
.. _Register: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives
* Install the development requirements into an environment::

$ pip install -e ".[dev]"

Or, if using Conda::

$ conda env create -f environment-dev.yml
$ pip install -e . --no-deps

* `Register your project with PyPI <https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives>`_.
* Enable GitHub Actions and Workflows (see below).
* Activate automated deployment with `Trusted Publishing`_ to PyPI when you push a new tag to the `main` branch.
* Add the repo to your `Read the Docs`_ account and turn on the ReadTheDocs service hook.
* Release your package by pushing a new tag to `main`.
* Update the `dependencies` field of your `pyproject.toml` file that specifies the packages you will need for
your project and their versions. For more info see the `pip docs for requirements files <https://pip.pypa.io/en/stable/user_guide/#requirements-files>`_.
* Register your project with `pre-commit.ci`_.
* Activate `dependabot`_ for your project.

For more details, see the `cookiecutter-pypackage tutorial`_.

.. _`cookiecutter-pypackage tutorial`: https://cookiecutter-pypackage.readthedocs.io/en/latest/tutorial.html
GitHub Actions
~~~~~~~~~~~~~~

In order to use GitHub Actions, you will need to enable them in your repo. To do so, go to the `Actions` tab of your repo and click the green button to enable them. Afterwards, you will need to ~generate a few Personal Access Tokens (PATs) <https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens>`_ to allow the workflows to run. To do so, go to the `Settings` tab of your repo and click on `Secrets` in the left sidebar. Then, click on the `New repository secret` button and add the following secrets:

* `BUMP_VERSION_TOKEN` with the following privileges:
- Contents: Read and Write
- Metadata: Read-Only
- Pull Requests: Read and Write

* `OPENSSF_SCORECARD_TOKEN` with the following privileges:
- Administration: Read-Only
- Metadata: Read-Only
- Webhooks: Read-Only

Trusted Publishing
~~~~~~~~~~~~~~~~~~

For Trusted Publishing with PyPI_ and TestPyPI_, you will need to create deployment environments in your repo. To do so, go to the `Settings` tab of your repo and click on `Environments` in the left sidebar. Then, click on the `New environment` button and add the following environments:

* `staging`
* `production`

Afterwards, you will need to configure your project on both PyPI_ and TestPyPI_ to accept uploads from GitHub Actions. To do so, go to the `Manage` tab of your project on PyPI and click on `Publishing` in the left sidebar. Then, click on the `Add a new publisher` button and fill in the following information:

* Owner: `my_username`
* Repository name: `my_project`
* Workflow name:
* For TestPyPI: `tag-testpypi.yml`
* For PyPI: `publish-pypi.yml`
* Environment name:
* For TestPyPI: `staging`
* For PyPI: `production`

Once this is configured, all you need to do is push a new tag to the `main` branch and your package will be automatically published to TestPyPI_, while performing a release on GitHub will then trigger an upload to PyPI_.

Not Exactly What You Want?
--------------------------
Expand Down Expand Up @@ -128,27 +160,44 @@ I also accept pull requests on this, if they're small, atomic, and if they make
.. _Mkdocs: https://pypi.org/project/mkdocs/
.. _Mypy: https://mypy.readthedocs.io/en/stable/
.. _Poetry: https://python-poetry.org/
.. _Pre-commit: https://pre-commit.com/
.. _Punch: https://github.com/lgiordani/punch
.. _PyPI: https://pypi.python.org/pypi
.. _Read the Docs: https://readthedocs.io/
.. _SemVer-2.0-compliant: https://semver.org/spec/v2.0.0.html
.. _Sphinx: http://sphinx-doc.org/
.. _Tox: http://testrun.org/tox/
.. _`pyproject.toml`: https://www.python.org/dev/peps/pep-0518/
.. _`pyup.io`: https://pyup.io/
.. _bump2version: https://github.com/c4urself/bump2version
.. _bump-my-version: https://github.com/callowayproject/bump-my-version
.. _bump2version: https://github.com/c4urself/bump2version
.. _cookiecutter-pypackage tutorial: https://cookiecutter-pypackage.readthedocs.io/en/latest/tutorial.html
.. _dependabot: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates
.. _flit: https://flit.pypa.io/en/stable/
.. _pre-commit.ci: https://pre-commit.ci/
.. _pre-commit: https://pre-commit.com/
.. _pypi: https://pypi.org/
.. _pyproject.toml: https://www.python.org/dev/peps/pep-0518/
.. _pyup.io: https://pyup.io/
.. _sphinx-intl: https://sphinx-intl.readthedocs.io/en/master/
.. _testpypi: https://test.pypi.org/

.. _GitHub comparison view: https://github.com/tony/cookiecutter-pypackage-pythonic/compare/audreyr:master...master
.. _`Nekroze/cookiecutter-pypackage`: https://github.com/Nekroze/cookiecutter-pypackage
.. _`ardydedase/cookiecutter-pypackage`: https://github.com/ardydedase/cookiecutter-pypackage
.. _`briggySmalls/cookiecutter-pypackage`: https://github.com/briggySmalls/cookiecutter-pypackage
.. _`family tree`: https://github.com/audreyr/cookiecutter-pypackage/network/members
.. _`lgiordani/cookiecutter-pypackage`: https://github.com/lgiordani/cookiecutter-pypackage
.. _`tony/cookiecutter-pypackage-pythonic`: https://github.com/tony/cookiecutter-pypackage-pythonic
.. _`veit/cookiecutter-namespace-template`: https://github.com/veit/cookiecutter-namespace-template
.. _`waynerv/cookiecutter-pypackage`: https://waynerv.github.io/cookiecutter-pypackage/
.. _`zillionare/cookiecutter-pypackage`: https://zillionare.github.io/cookiecutter-pypackage/
.. _Nekroze/cookiecutter-pypackage: https://github.com/Nekroze/cookiecutter-pypackage
.. _ardydedase/cookiecutter-pypackage: https://github.com/ardydedase/cookiecutter-pypackage
.. _briggySmalls/cookiecutter-pypackage: https://github.com/briggySmalls/cookiecutter-pypackage
.. _family tree: https://github.com/audreyr/cookiecutter-pypackage/network/members
.. _lgiordani/cookiecutter-pypackage: https://github.com/lgiordani/cookiecutter-pypackage
.. _network: https://github.com/audreyr/cookiecutter-pypackage/network
.. _tony/cookiecutter-pypackage-pythonic: https://github.com/tony/cookiecutter-pypackage-pythonic
.. _veit/cookiecutter-namespace-template: https://github.com/veit/cookiecutter-namespace-template
.. _waynerv/cookiecutter-pypackage: https://waynerv.github.io/cookiecutter-pypackage/
.. _zillionare/cookiecutter-pypackage: https://zillionare.github.io/cookiecutter-pypackage/

.. |build| image:: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml/badge.svg
:target: https://github.com/Ouranosinc/cookiecutter-pypackage/actions/workflows/main.yml
:alt: Build Status

.. |docs-upstream| image:: https://readthedocs.org/projects/cookiecutter-pypackage/badge/?version=latest
:target: https://cookiecutter-pypackage.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status

.. |pyup-upstream| image:: https://pyup.io/repos/github/audreyfeldroy/cookiecutter-pypackage/shield.svg
:target: https://pyup.io/repos/github/audreyfeldroy/cookiecutter-pypackage/
:alt: Updates
3 changes: 2 additions & 1 deletion hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ def remove_folder(folder_path):

def replace_contents(filepath):
replacements = {
"__BUMPVERSION_TOKEN__": "secrets.BUMPVERSION_TOKEN",
"__BUMP_VERSION_TOKEN__": "secrets.BUMP_VERSION_TOKEN",
"__GITHUB_REF__": "github.ref",
"__GITHUB_REF_NAME__": "github.ref_name",
"__GITHUB_TOKEN__": "secrets.GITHUB_TOKEN",
"__PYTHON_VERSION__": "matrix.python-version",
"__TOX_ENV__": "matrix.tox-env",
"__OPENSSF_SCORECARD_TOKEN__": "secrets.OPENSSF_SCORECARD_TOKEN",
}

lines = []
Expand Down
6 changes: 4 additions & 2 deletions tests/test_bake_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def test_bake_with_apostrophe_and_run_tests(cookies):
assert result.project_path.is_dir()
assert run_inside_dir("python -m coverage", str(result.project_path)) == 0


def test_bake_without_translations(cookies):
with bake_in_temp_dir(cookies, extra_context={"add_translations": "n"}) as result:
found_toplevel_files = [f.name for f in result.project_path.iterdir()]
Expand All @@ -146,6 +147,7 @@ def test_bake_without_translations(cookies):
with open(str(pyproject_path)) as pyproject_file:
assert "sphinx-intl" not in pyproject_file.read()


def test_bake_without_docs(cookies):
with bake_in_temp_dir(cookies, extra_context={"make_docs": "n"}) as result:
found_toplevel_files = [f.name for f in result.project_path.iterdir()]
Expand Down Expand Up @@ -333,8 +335,8 @@ def test_black(cookies, use_black, expected):
with bake_in_temp_dir(cookies, extra_context={"use_black": use_black}) as result:
assert result.project_path.is_dir()
requirements_path = result.project_path.joinpath("pyproject.toml")
assert ("black>=" in requirements_path.read_text()) is expected
assert ("isort>=" in requirements_path.read_text()) is expected
assert ("black==" in requirements_path.read_text()) is expected
assert ("isort==" in requirements_path.read_text()) is expected
assert ("[tool.black]" in requirements_path.read_text()) is expected
makefile_path = result.project_path.joinpath("Makefile")
assert ("black --check" in makefile_path.read_text()) is expected
15 changes: 15 additions & 0 deletions {{cookiecutter.project_slug}}/.github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
time: '12:00'
open-pull-requests-limit: 10

- package-ecosystem: pip
directory: /
schedule:
interval: daily
time: '12:00'
open-pull-requests-limit: 10
49 changes: 49 additions & 0 deletions {{cookiecutter.project_slug}}/.github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# label rules used by .github/workflows/label.yml

# label 'ci' all automation-related steps and files
# Since this repository is in itself an automation process to deploy a server instance,
# we refer here to CI as the 'meta' configuration files for managing the code and integrations with the repository,
# not configurations related to the deployment process itself.

# Uncomment the following lines to enable the labeler (requires labels with the same name to exist in the repository)

# label 'ci' all automation-related steps and files
#'CI':
# - changed-files:
# - any-glob-to-any-file:
# - '.editorconfig'
# - '.flake8'
# - '.pre-commit-config.yaml'
{%- if cookiecutter.make_docs != 'y' %}
# - '.readthedocs.yml'
{%- endif %}
# - '.yamllint.yml'
# - '.github/workflows/*'
{%- if cookiecutter.make_docs != 'y' %}
# - 'docs/Makefile'
{%- endif %}
# - 'tox.ini'
# - 'Makefile'

{%- if cookiecutter.make_docs != 'y' %}
# label 'docs' all documentation-related steps and files
#'docs':
# - changed-files:
# - any-glob-to-any-file:
# - '.readthedocs.yml'
{%- if cookiecutter.open_source_license != 'Not open source' %}
# - '.zenodo.json'
{%- endif %}
# - 'docs/**/*'
# - 'environment-docs.yml'
{%- if cookiecutter.create_author_file != 'y' %}
# - 'AUTHORS.rst'
{%- endif %}
# - 'CONTRIBUTING.rst'
# - 'CODE_OF_CONDUCT.md'
# - 'DISCUSSION_TEMPLATE/**/*'
# - 'ISSUE_TEMPLATE/**/*'
# - 'ISSUE_TEMPLATE.md'
# - 'PULL_REQUEST_TEMPLATE.md'
# - 'README.rst'
{%- endif %}

This file was deleted.

24 changes: 20 additions & 4 deletions {{cookiecutter.project_slug}}/.github/workflows/bump-version.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# This workflow requires a personal access token named `BUMPVERSION_TOKEN` with the following privileges:
# - repo
# - workflow
# This workflow requires a personal access token named `BUMP_VERSION_TOKEN` with the following privileges:
# - Contents: Read and Write
# - Metadata: Read-Only
# - Pull Requests: Read and Write

name: "Bump Patch Version"

Expand Down Expand Up @@ -39,10 +40,25 @@ on:
- {{ cookiecutter.project_slug }}/__init__.py
workflow_dispatch:

permissions:
contents: read

jobs:
bump_patch_version:
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
steps:
- name: Harden Runner
uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
files.pythonhosted.org:443
github.com:443
pypi.org:443
- uses: actions/checkout@v4
with:
persist-credentials: false
Expand All @@ -65,5 +81,5 @@ jobs:
uses: ad-m/github-push-action@master
with:
force: false
github_token: __BUMPVERSION_TOKEN__
github_token: __BUMP_VERSION_TOKEN__
branch: __GITHUB_REF__
Loading

0 comments on commit f091c34

Please sign in to comment.