diff --git a/.github/chronographer.yml b/.github/chronographer.yml new file mode 100644 index 00000000..24168796 --- /dev/null +++ b/.github/chronographer.yml @@ -0,0 +1,11 @@ +--- +enforce_name: + suffix: .md +exclude: + bots: + - dependabot-preview + - dependabot + - patchback + humans: + - pyup-bot +... diff --git a/CHANGELOG.md b/CHANGELOG.md index 4253fd03..4f9699b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +[//]: # (DO-NOT-REMOVE-versioning-promise-START) + +```{note} +The change notes follow [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +except for the title formatting, and this project adheres to [Semantic +Versioning](https://semver.org/spec/v2.0.0.html). +``` + + + + + ## 0.16.1 - 2021-12-16 ✨ NEW: Add `myst_linkify_fuzzy_links` option. diff --git a/docs/changelog-fragments.d/.CHANGELOG-TEMPLATE.md.j2 b/docs/changelog-fragments.d/.CHANGELOG-TEMPLATE.md.j2 new file mode 100644 index 00000000..b231e9b2 --- /dev/null +++ b/docs/changelog-fragments.d/.CHANGELOG-TEMPLATE.md.j2 @@ -0,0 +1,31 @@ + +{% for section, _ in sections.items() %} +{% set title_prefix = underlines[0] %} +{% if section %} +{{ title_prefix }} {{ section }} +{% set title_prefix = underlines[1] %} +{% endif %} + +{% if sections[section] %} +{% for category, val in definitions.items() if category in sections[section] %} +{{ title_prefix }} {{ definitions[category]['name'] }} +{% if definitions[category]['showcontent'] %} + +{% for text, values in sections[section][category].items() %} +* {{ text }} + ({{ values|join(',\n ') }}) +{% endfor -%} + +{% else %} +* {{ sections[section][category]['']|join(', ') }} +{% endif %} + +{% if sections[section][category]|length == 0 %} +No significant changes. +{% endif %} +{% endfor %} + +{% else %} +No significant changes. +{% endif %} +{% endfor %} diff --git a/docs/changelog-fragments.d/.gitignore b/docs/changelog-fragments.d/.gitignore new file mode 100644 index 00000000..46978d22 --- /dev/null +++ b/docs/changelog-fragments.d/.gitignore @@ -0,0 +1,25 @@ +* +!.CHANGELOG-TEMPLATE.md.j2 +!.gitignore +!README.md +!*.bugfix +!*.bugfix.md +!*.bugfix.*.md +!*.breaking +!*.breaking.md +!*.breaking.*.md +!*.deprecation +!*.deprecation.md +!*.deprecation.*.md +!*.doc +!*.doc.md +!*.doc.*.md +!*.feature +!*.feature.md +!*.feature.*.md +!*.internal +!*.internal.md +!*.internal.*.md +!*.misc +!*.misc.md +!*.misc.*.md diff --git a/docs/changelog-fragments.d/454.misc.md b/docs/changelog-fragments.d/454.misc.md new file mode 100644 index 00000000..d4652c91 --- /dev/null +++ b/docs/changelog-fragments.d/454.misc.md @@ -0,0 +1,4 @@ +Added changelog fragment management infrastructure using [Towncrier] +-- by {user}`webknjaz` + +[Towncrier]: https://github.com/twisted/towncrier diff --git a/docs/changelog-fragments.d/README.md b/docs/changelog-fragments.d/README.md new file mode 100644 index 00000000..bb9677a6 --- /dev/null +++ b/docs/changelog-fragments.d/README.md @@ -0,0 +1,79 @@ + + +(_myst_parser_adding_changelog_fragments)= + +## Adding change notes with your PRs + +It is very important to maintain a log for news of how +updating to the new version of the software will affect +end-users. This is why we enforce collection of the change +fragment files in pull requests as per [Towncrier philosophy]. + +The idea is that when somebody makes a change, they must record +the bits that would affect end-users only including information +that would be useful to them. Then, when the maintainers publish +a new release, they'll automatically use these records to compose +a change log for the respective version. It is important to +understand that including unnecessary low-level implementation +related details generates noise that is not particularly useful +to the end-users most of the time. And so such details should be +recorded in the Git history rather than a changelog. + +## Alright! So how do I add a news fragment? + +To submit a change note about your PR, add a text file into the +`docs/changelog-fragments.d/` folder. It should contain an +explanation of what applying this PR will change in the way +end-users interact with the project. One sentence is usually +enough but feel free to add as many details as you feel necessary +for the users to understand what it means. + +**Use the past tense** for the text in your fragment because, +combined with others, it will be a part of the "news digest" +telling the readers **what changed** in a specific version of +the library *since the previous version*. You should also use +[MyST Markdown] syntax for highlighting code (inline or block), +linking parts of the docs or external sites. +At the end, sign your change note by adding ```-- by +{user}`github-username``` (replace `github-username` with +your own!). + +Finally, name your file following the convention that Towncrier +understands: it should start with the number of an issue or a +PR followed by a dot, then add a patch type, like `feature`, +`bugfix`, `doc`, `misc` etc., and add `.md` as a suffix. If you +need to add more than one fragment, you may add an optional +sequence number (delimited with another period) between the type +and the suffix. + +## Examples for changelog entries adding to your Pull Requests + +File `docs/changelog-fragments.d/666.doc.md`: + +```md +Added a `{user}` role to Sphinx config -- by {user}`webknjaz` +``` + +File `docs/changelog-fragments.d/116.feature.md`: + +```md +Added support for nested module options (suboptions) +-- by {user}`tomaciazek` +``` + +File `docs/changelog-fragments.d/140.bugfix.md`: + +```md +Implemented opening standalone Ansible files that have no workspace +associated -- by {user}`ganeshrn` +``` + +```{tip} +See `pyproject.toml` for all available categories +(`tool.towncrier.type`). +``` + +[MyST Markdown]: +https://myst-parser.rtfd.io/en/latest/syntax/syntax.html +[Towncrier philosophy]: +https://towncrier.rtfd.io/en/actual-freaking-docs/#philosophy diff --git a/docs/conf.py b/docs/conf.py index 9f244fd8..7637087b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,17 +4,44 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html +from functools import partial +from pathlib import Path + +from setuptools_scm import get_version + from sphinx.application import Sphinx from sphinx.util.docutils import SphinxDirective from myst_parser import __version__ + +# -- Path setup -------------------------------------------------------------- + +PROJECT_ROOT_DIR = Path(__file__).parents[1].resolve() # pylint: disable=no-member +get_scm_version = partial(get_version, root=PROJECT_ROOT_DIR) # -- Project information ----------------------------------------------------- +github_url = 'https://github.com' +github_repo_org = 'ansible' +github_repo_name = 'ansible-language-server' +github_repo_slug = f'{github_repo_org}/{github_repo_name}' +github_repo_url = f'{github_url}/{github_repo_slug}' +github_sponsors_url = f'{github_url}/sponsors' + project = "MyST Parser" copyright = "2020, Executable Book Project" author = "Executable Book Project" -version = __version__ + +# The short X.Y version +version = '.'.join( + get_scm_version( + local_scheme='no-local-version', + ).split('.')[:3], +) + +# The full version, including alpha/beta/rc tags +release = get_scm_version() + master_doc = "index" language = "en" @@ -27,6 +54,7 @@ extensions = [ "myst_parser", "sphinx.ext.autodoc", + 'sphinx.ext.extlinks', "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinxcontrib.bibtex", @@ -34,6 +62,7 @@ "sphinxext.rediraffe", "sphinxcontrib.mermaid", "sphinxext.opengraph", + 'sphinxcontrib.towncrier', # provides `towncrier-draft-entries` directive ] # Add any paths that contain templates here, relative to this directory. @@ -42,7 +71,10 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +exclude_patterns = [ + "_build", "Thumbs.db", ".DS_Store", + 'changelog-fragments.d/**', # Towncrier-managed change notes +] # -- Options for HTML output ------------------------------------------------- @@ -88,6 +120,12 @@ "substitution", "tasklist", ] +myst_substitutions = { + 'project': project, + 'release': release, + 'release_l': f'`{release}`', # Needed in draft changelog for spelling ext + 'version': version, +} myst_heading_anchors = 2 myst_footnote_transition = True myst_dmath_double_inline = True @@ -102,6 +140,14 @@ } +# -- Options for towncrier_draft extension ----------------------------------- + +towncrier_draft_autoversion_mode = 'draft' # or: 'sphinx-version', 'sphinx-release' +towncrier_draft_include_empty = True +towncrier_draft_working_directory = PROJECT_ROOT_DIR +# Not yet supported: towncrier_draft_config_path = 'pyproject.toml' # relative to cwd + + def run_apidoc(app): """generate apidoc @@ -137,6 +183,16 @@ def run_apidoc(app): os.remove(os.path.join(api_folder, "modules.rst")) +# -- Options for extlinks extension ------------------------------------------ + +extlinks = { + 'issue': (f'{github_repo_url}/issues/%s', '#'), # noqa: WPS323 + 'pr': (f'{github_repo_url}/pull/%s', 'PR #'), # noqa: WPS323 + 'commit': (f'{github_repo_url}/commit/%s', ''), # noqa: WPS323 + 'gh': (f'{github_url}/%s', 'GitHub: '), # noqa: WPS323 + 'user': (f'{github_sponsors_url}/%s', '@'), # noqa: WPS323 +} + intersphinx_mapping = { "python": ("https://docs.python.org/3.7", None), "sphinx": ("https://www.sphinx-doc.org/en/master", None), diff --git a/docs/develop/_changelog.md b/docs/develop/_changelog.md index d24e7ac0..d2b3fa0e 100644 --- a/docs/develop/_changelog.md +++ b/docs/develop/_changelog.md @@ -1,4 +1,23 @@ +# Changelog + +```{include} ../../CHANGELOG.md +:end-before: +:start-after: (DO-NOT-REMOVE-versioning-promise-START) + +``` + + +## {{ release_l }}, as of {sub-ref}`today` _{subscript}`/UNRELEASED DRAFT/`_ + +```{important} This version is not yet released and is under active development +``` + +```{towncrier-draft-entries} +``` + ```{include} ../../CHANGELOG.md :relative-docs: docs/ :relative-images: +:start-after: + ``` diff --git a/docs/develop/contributing.md b/docs/develop/contributing.md index 32d60dbe..a6e37ccc 100644 --- a/docs/develop/contributing.md +++ b/docs/develop/contributing.md @@ -71,6 +71,9 @@ For documentation build tests: >> make html-strict ``` +```{include} ../changelog-fragments.d/README.md +``` + ```{seealso} {ref}`develop/testing` ``` diff --git a/pyproject.toml b/pyproject.toml index c6de55b4..2323a1ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,3 +8,50 @@ known_first_party = ["myst_parser", "tests"] known_third_party = ["docutils", "markdown_it", "sphinx"] # Group first party and local folder imports together no_lines_before = "LOCALFOLDER" + +[tool.towncrier] + directory = "docs/changelog-fragments.d/" + filename = "CHANGELOG.md" + issue_format = "{{issue}}`{issue}`" + start_string = "\n\n" + template = "docs/changelog-fragments.d/.CHANGELOG-TEMPLATE.md.j2" + title_format = "## {version} - ({project_date})" + underlines = ["##", "###", "####", "#####"] + + [[tool.towncrier.section]] + path = "" + + [[tool.towncrier.type]] + directory = "bugfix" + name = "Bugfixes" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Features" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations (removal in next major release)" + showcontent = true + + [[tool.towncrier.type]] + directory = "breaking" + name = "Backward incompatible changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "doc" + name = "Documentation" + showcontent = true + + [[tool.towncrier.type]] + directory = "misc" + name = "Miscellaneous" + showcontent = true + + [[tool.towncrier.type]] + directory = "internal" + name = "Contributor-facing changes" + showcontent = true diff --git a/setup.cfg b/setup.cfg index 4f7ddcbe..44c003ab 100644 --- a/setup.cfg +++ b/setup.cfg @@ -65,12 +65,14 @@ linkify = # Note: This is only required for internal use rtd = ipython + setuptools-scm ~= 6.3.2 sphinx-book-theme~=0.1.0 sphinx-panels~=0.5.2 sphinxcontrib-bibtex~=2.1 sphinxext-rediraffe~=0.2 sphinxcontrib.mermaid~=0.6.3 sphinxext-opengraph~=0.4.2 + sphinxcontrib-towncrier ~= 0.2.0a0 testing = beautifulsoup4 coverage diff --git a/tox.ini b/tox.ini index c826391d..83ea6050 100644 --- a/tox.ini +++ b/tox.ini @@ -34,6 +34,11 @@ extras = whitelist_externals = rm echo + git +commands_pre = + # Retrieve possibly missing commits: + -git fetch --unshallow + -git fetch --tags commands = clean: rm -rf docs/_build sphinx-build -nW --keep-going -b {posargs:html} docs/ docs/_build/{posargs:html} @@ -52,6 +57,41 @@ commands = -n -b {posargs:html} docs/ docs/_build/{posargs:html} +[testenv:make-changelog] +basepython = python3 +depends = + check-changelog +description = + Generate a changelog from fragments using Towncrier. Getting an + unreleased changelog preview does not require extra arguments. + When invoking to update the changelog, pass the desired version as an + argument after `--`. For example, `tox -e {envname} -- 1.3.2`. +commands = + {envpython} -m \ + towncrier.build \ + --version \ + {posargs:'[UNRELEASED DRAFT]' --draft} +deps = + towncrier == 21.3.0 +isolated_build = true +skip_install = true + + +[testenv:check-changelog] +basepython = {[testenv:make-changelog]basepython} +description = + Check Towncrier change notes +commands = + {envpython} -m \ + towncrier.check \ + --compare-with origin/master \ + {posargs:} +deps = + {[testenv:make-changelog]deps} +isolated_build = {[testenv:make-changelog]isolated_build} +skip_install = {[testenv:make-changelog]skip_install} + + [pytest] addopts = --ignore=setup.py markers =