Initial setup for towncrier

pull/1931/head
Kieran R. Prasch 2020-04-24 10:54:58 -07:00
parent 736ad96294
commit dda6123742
5 changed files with 127 additions and 0 deletions

1
newsfragments/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
!.gitignore

24
newsfragments/README.md Normal file
View File

@ -0,0 +1,24 @@
This directory collects "newsfragments": short files that each contain
a snippet of ReST-formatted text that will be added to the next
release notes. This should be a description of aspects of the change
(if any) that are relevant to users. (This contrasts with the
commit message and PR description, which are a description of the change as
relevant to people working on the code itself.)
Each file should be named like `<ISSUE>.<TYPE>.rst`, where
`<ISSUE>` is an issue number, and `<TYPE>` is one of:
* `feature`
* `bugfix`
* `doc`
* `misc`
So for example: `123.feature.rst`, `456.bugfix.rst`
If the PR fixes an issue, use that number here. If there is no issue,
then open up the PR first and use the PR number for the newsfragment.
Note that the `towncrier` tool will automatically
reflow your text, so don't try to do any fancy formatting. Run
`towncrier --draft` to get a preview of what the release notes entry
will look like in the final release notes.

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# Towncrier silently ignores files that do not match the expected ending.
# We use this script to ensure we catch these as errors in CI.
import pathlib
class InvalidNewsFragment(RuntimeError):
pass
ALLOWED_EXTENSIONS = {
'.feature.rst',
'.bugfix.rst',
'.doc.rst',
'.removal.rst',
'.misc.rst',
}
ALLOWED_FILES = {
'validate_files.py',
'README.md',
'.gitignore'
}
THIS_DIR = pathlib.Path(__file__).parent
for fragment_file in THIS_DIR.iterdir():
if fragment_file.name in ALLOWED_FILES:
continue
full_extension = "".join(fragment_file.suffixes)
if full_extension not in ALLOWED_EXTENSIONS:
raise InvalidNewsFragment(f"Unexpected newsfragment file: {fragment_file}")

8
pyproject.toml Normal file
View File

@ -0,0 +1,8 @@
[tool.towncrier]
package="nucypher"
package_dir="nucypher"
filename = "docs/source/release_notes/releases.rst"
directory = "newsfragments"
underlines = ["-", "~", "^", "*"]
issue_format = "`#{issue} <https://github.com/nucypher/nucypher/issues/{issue}>`__"
title_format = "v{version} ({project_date})"

View File

@ -0,0 +1,58 @@
import subprocess
import sys
import venv
from pathlib import (
Path,
)
from tempfile import (
TemporaryDirectory,
)
from typing import (
Tuple,
)
def create_venv(parent_path: Path) -> Path:
if hasattr(sys, 'real_prefix'):
# python is currently running inside a venv
# pip_path = Path(sys.executable).parent
raise RuntimeError("Disable venv and try again.")
venv_path = parent_path / 'package-smoke-test'
pip_path = venv_path / 'bin' / 'pip'
venv.create(venv_path, with_pip=True)
assert Path.exists(venv_path), f'venv path "{venv_path}" does not exist.'
assert Path.exists(pip_path), f'pip executable not found at "{pip_path}"'
subprocess.run([pip_path, 'install', '-U', 'pip', 'setuptools'], check=True)
return venv_path
def find_wheel(project_path: Path) -> Path:
wheels = list(project_path.glob('dist/*.whl'))
if len(wheels) != 1:
raise Exception(f"Expected one wheel. Instead found: {wheels} in project {project_path.absolute()}")
return wheels[0]
def install_wheel(venv_path: Path, wheel_path: Path, extras: Tuple[str, ...] = ()) -> None:
if extras:
extra_suffix = f"[{','.join(extras)}]"
else:
extra_suffix = ""
subprocess.run([venv_path / 'bin' / 'pip', 'install', f"{wheel_path}{extra_suffix}"], check=True)
def test_install_local_wheel() -> None:
with TemporaryDirectory() as tmpdir:
venv_path = create_venv(Path(tmpdir))
wheel_path = find_wheel(Path('.'))
install_wheel(venv_path, wheel_path)
print("Installed", wheel_path.absolute(), "to", venv_path)
print(f"Activate with `source {venv_path}/bin/activate`")
input("Press enter when the test has completed. The directory will be deleted.")
if __name__ == '__main__':
test_install_local_wheel()