diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..5262e23c --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,24 @@ +categories: + - title: "New Features" + labels: + - "enhancement" + - title: "Maintenance" + labels: + - "maintenance" + - title: "Bug Fixes" + labels: + - "bug" + - title: "Specifications and Documentation" + label: + - "specification" + - "doc" + - title: "Tooling" + label: + - "tooling" +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +template: | + Special thanks to the contributors that made this release happen: $CONTRIBUTORS + + ## Full list of changes + + $CHANGES diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 7c1a6a53..fa9af8d0 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,18 +1,16 @@ - { +{ // Configuration file for RenovateBot: https://docs.renovatebot.com/configuration-options extends: ["config:base"], labels: ["dependencies"], // For convenient searching in GitHub pip_requirements: { - fileMatch: ["^tox.ini$"] - }, - pip_setup: { - fileMatch: ["^pyproject.toml$", "(^|/)setup\\.py$"] + fileMatch: ["^tox.ini$", "(^|/)requirements([\\w-]*)\\.txt$"] }, packageRules: [ { // Automerge patches, pin changes and digest changes. // Also groups these changes together. - groupName: "patch updates", + groupName: "bugfixes", + excludePackagePrefixes: ["dev", "lint", "types"], matchUpdateTypes: ["patch", "pin", "digest"], prPriority: 3, // Patches should go first! automerge: true @@ -28,18 +26,32 @@ // GitHub Actions are higher priority to update than most dependencies. groupName: "GitHub Actions", matchManagers: ["github-actions"], - prPriority: 1 + prPriority: 1, + automerge: true, }, // Everything not in one of these rules gets priority 0 and falls here. { // Minor changes can be grouped and automerged for dev dependencies, but are also deprioritised. - groupName: "development dependencies (minor and patch)", + groupName: "development dependencies (non-major)", groupSlug: "dev-dependencies", - matchDepTypes: ["devDependencies"], + matchPackagePrefixes: [ + "dev", + "lint", + "types" + ], + excludePackagePatterns: ["ruff"], matchUpdateTypes: ["minor", "patch", "pin", "digest"], prPriority: -1, automerge: true }, + { + // Documentation related updates + groupName: "documentation dependencies", + groupSlug: "doc-dependencies", + matchPackageNames: ["Sphinx"], + matchPackagePatterns: ["^[Ss]phinx.*$", "^furo$"], + matchPackagePrefixes: ["docs"], + }, { // Other major dependencies get deprioritised below minor dev dependencies. matchUpdateTypes: ["major"], @@ -52,6 +64,12 @@ matchDepTypes: ["devDependencies"], matchUpdateTypes: ["major"], prPriority: -3 + }, + { + // Ruff is still unstable, so update it separately. + groupName: "ruff", + matchPackagePatterns: ["^(lint/)?ruff$"], + prPriority: -3 } ], regexManagers: [ @@ -60,14 +78,22 @@ fileMatch: ["tox.ini"], depTypeTemplate: "devDependencies", matchStrings: [ - "# renovate: datasource=(?\S+)\n\s+(?.*?)(\[[\w]*\])*[=><]=?(?.*?)\n" + "# renovate: datasource=(?\\S+)\n\\s+(?.*?)(\\[[\\w]*\\])*[=><]=?(?.*?)\n" + ] + }, + { + // .pre-commit-config.yaml version updates + fileMatch: [".pre-commit-config.yaml"], + depTypeTemplate: "devDependencies", + matchStrings: [ + "# renovate: datasource=(?\\S+);\\s*depName=(?.*?)\n\s+rev: \"v?(?.*?)\"" ] } ], timezone: "Etc/UTC", - automergeSchedule: "after 1 am and before 7 am", + automergeSchedule: "every weekend", schedule: "every weekend", - prConcurrentLimit: 5, // No more than 5 open PRs at a time. + prConcurrentLimit: 2, // No more than 2 open PRs at a time. prCreation: "not-pending", // Wait until status checks have completed before raising the PR prNotPendingHours: 4, // ...unless the status checks have been running for 4+ hours. prHourlyLimit: 1, // No more than 1 PR per hour. diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 00000000..4026a0da --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,37 @@ +name: Documentation +on: + push: + branches: + - "main" + - "feature/*" + - "hotfix/*" + - "release/*" + pull_request: + paths: + - "docs/**" + - "pyproject.toml" + - ".github/workflows/docs.yaml" + +jobs: + sphinx: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + - name: Install Tox + run: pip install tox + - name: Lint documentation + run: tox run -e lint-docs + - name: Build documentation + run: tox run -e build-docs + - name: Upload documentation + uses: actions/upload-artifact@v3 + with: + name: docs + path: docs/_build/ diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml index 8c79f119..e60ebc18 100644 --- a/.github/workflows/release-drafter.yaml +++ b/.github/workflows/release-drafter.yaml @@ -4,7 +4,7 @@ on: push: # branches to consider in the event; optional, defaults to all branches: - - master + - main jobs: update_release_draft: diff --git a/.gitignore b/.gitignore index e5d55da9..b19a46a2 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,9 @@ dmypy.json # Test results /results/ + +# direnv +.envrc + +# Ignore version module generated by setuptools_scm +/*/_version.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..5a9b3a40 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,30 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-merge-conflict + - id: check-toml + - id: fix-byte-order-marker + - id: mixed-line-ending + - repo: https://github.com/charliermarsh/ruff-pre-commit + # renovate: datasource=pypi;depName=ruff + rev: "v0.0.267" + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - repo: https://github.com/psf/black + # renovate: datasource=pypi;depName=black + rev: "23.3.0" + hooks: + - id: black + - repo: https://github.com/adrienverge/yamllint.git + # renovate: datasource=pypi;depName=yamllint + rev: "v1.31.0" + hooks: + - id: yamllint diff --git a/HACKING.rst b/HACKING.rst index 47a588fd..64afaadb 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -16,6 +16,7 @@ We use a large number of tools for our project. Most of these are installed for - tox_ version 4 or later. (3.8+ will automatically provision a v4 virtualenv) - Pyright_ (it's recommended you install with ``snap install --classic pyright``) - ShellCheck_ (also available via snap: ``snap install shellcheck``) +- pre-commit_ Once you have all of those installed, you can install the necessary virtual environments for this repository using tox. @@ -44,6 +45,8 @@ If you'd like to run the tests with a newer version of Python, you can pass a sp tox -e test-py310 +While the use of pre-commit_ is optional, it is highly encouraged, as it runs automatic fixes for files when `git commit` is called, including code formatting with ``black`` and ``ruff``. The versions available in ``apt`` from Debian 11 (bullseye), Ubuntu 22.04 (jammy) and newer are sufficient, but you can also install the latest with ``pip install pre-commit``. Once you've installed it, run ``pre-commit install`` in this git repository to install the pre-commit hooks. + Tox environments and labels ########################### @@ -68,6 +71,7 @@ Running ``tox run -m format`` and ``tox run -m lint`` before committing code is .. _`Canonical contributor licence agreement`: http://www.ubuntu.com/legal/contributors/ .. _deadsnakes: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa .. _`git submodules`: https://git-scm.com/book/en/v2/Git-Tools-Submodules#_cloning_submodules +.. _pre-commit: https://pre-commit.com/ .. _pyproject.toml: ./pyproject.toml .. _Pyright: https://github.com/microsoft/pyright .. _pytest: https://pytest.org diff --git a/docs/index.rst b/docs/index.rst index 81a3082a..02c4cfc9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,9 +36,9 @@ Craft-Application Project and community ===================== -Craft-Application is a member of the Canonical family. It's an open source project -that warmly welcomes community projects, contributions, suggestions, fixes -and constructive feedback. +Craft-Application is a member of the Canonical family. It's an open source +project that warmly welcomes community projects, contributions, suggestions, +fixes and constructive feedback. * `Ubuntu Code of Conduct `_. * `Canonical contributor licenses agreement diff --git a/pyproject.toml b/pyproject.toml index 97d751ac..7ba62f44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,6 @@ [project] name = "starcraft" -version = "0.0.1" -readme = "README.rst" +dynamic = ["version", "readme"] dependencies = [ ] @@ -18,19 +17,27 @@ starcraft-hello = "starcraft:hello" [project.optional-dependencies] dev = [ - "coverage[toml]==7.2.2", + "coverage[toml]==7.2.5", "pytest==7.3.1", "pytest-cov==4.0.0", "pytest-mock==3.10.0", ] +lint = [ + "black==23.3.0", + "codespell[toml]==2.2.4", + "ruff==0.0.269", + "yamllint==1.32.0" +] types = [ + "mypy[reports]==1.3.0", + "pyright==1.1.309", ] docs = [ - "furo==2022.12.07", - "sphinx==5.3.0", + "furo==2023.5.20", + "sphinx>=6.2.1,<7.0", "sphinx-autobuild==2021.3.14", - "sphinx-copybutton==0.5.1", - "sphinx-design==0.3.0", + "sphinx-copybutton==0.5.2", + "sphinx-design==0.4.1", "sphinx-pydantic==0.1.1", "sphinx-toolbox==3.4.0", "sphinx-lint==0.6.7", @@ -38,10 +45,17 @@ docs = [ [build-system] requires = [ - "setuptools==67.8.0", + "setuptools==67.7.2", + "setuptools_scm[toml]>=7.1" ] build-backend = "setuptools.build_meta" +[tool.setuptools.dynamic] +readme = {file = "README.rst"} + +[tool.setuptools_scm] +write_to = "craft_application/_version.py" + [tool.setuptools.packages.find] exclude = [ "dist", @@ -155,6 +169,7 @@ extend-select = [ # Annotations: https://github.com/charliermarsh/ruff#flake8-annotations-ann "ANN0", # Type annotations for arguments other than `self` and `cls` "ANN2", # Return type annotations + "B026", # Keyword arguments must come after starred arguments # flake8-bandit: security testing. https://github.com/charliermarsh/ruff#flake8-bandit-s # https://bandit.readthedocs.io/en/latest/plugins/index.html#complete-test-plugin-listing "S101", "S102", # assert or exec @@ -167,7 +182,6 @@ extend-select = [ "S701", # jinja2 templates without autoescape "B0", # Common mistakes and typos. "RUF001", "RUF002", "RUF003", # Ambiguous unicode characters - "RUF004", # Keyword arguments must come after starred arguments "RUF005", # Encourages unpacking rather than concatenation "RUF100", # #noqa directive that doesn't flag anything. ] diff --git a/tox.ini b/tox.ini index b0428ee4..79a06e48 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] env_list = # Environments to run when called with no parameters. lint-{black,ruff,pyright,shellcheck,codespell,docs} - test-py38 -minversion = 4.3.5 + test-{py38,py310,py311} +minversion = 4.5 # Tox will use these requirements to bootstrap a venv if necessary. # tox-igore-env-name-mismatch allows us to have one virtualenv for all linting. # By setting requirements here, we make this INI file compatible with older @@ -11,9 +11,7 @@ minversion = 4.3.5 # install tox from apt. Older than that, the user gets an upgrade warning. requires = # renovate: datasource=pypi - tox==4.4.8 - # renovate: datasource=pypi - tox-ignore-env-name-mismatch==0.2.0.post2 + tox-ignore-env-name-mismatch>=0.2.0.post2 # Allow tox to access the user's $TMPDIR environment variable if set. # This workaround is required to avoid circular dependencies for TMPDIR, # since tox will otherwise attempt to use the environment's TMPDIR variable. @@ -49,16 +47,8 @@ labels = commands = pytest {tty:--color=yes} --junit-xml=results/test-results-{env_name}.xml tests/integration {posargs} [lint] # Standard linting configuration -skip_install = true -deps = - # renovate: datasource=pypi - black==23.3.0 - # renovate: datasource=pypi - ruff==0.0.260 - # renovate: datasource=pypi - codespell[tomli]==2.2.4 - # renovate: datasource=pypi - yamllint==1.31.0 +package = editable +extras = lint env_dir = {work_dir}/linting runner = ignore_env_name_mismatch @@ -76,30 +66,24 @@ commands_pre = shellcheck: bash -c '{[shellcheck]find} | {[shellcheck]filter} > {env_tmp_dir}/shellcheck_files' commands = black: black --check --diff {tty:--color} {posargs} . - ruff: ruff --diff --respect-gitignore {posargs} . + ruff: ruff check --respect-gitignore {posargs} . shellcheck: xargs -ra {env_tmp_dir}/shellcheck_files shellcheck codespell: codespell --toml {tox_root}/pyproject.toml {posargs} yaml: yamllint {posargs} . [testenv:lint-{mypy,pyright}] description = Static type checking -base = testenv -deps = - # renovate: datasource=pypi - mypy[reports]==1.3.0 +base = testenv, lint env_dir = {work_dir}/typing -runner = ignore_env_name_mismatch -package = editable -extras = [dev, types] +extras = dev, types labels = lint, type allowlist_externals = - pyright: pyright mypy: mkdir commands_pre = mypy: mkdir -p .mypy_cache commands = - pyright: pyright --lib {posargs} - mypy: mypy --install-types --non-interactive . + pyright: pyright {posargs} + mypy: mypy --install-types --non-interactive {posargs:.} [testenv:format-{black,ruff,codespell}] description = Automatically format source code @@ -117,21 +101,21 @@ no_package = true env_dir = {work_dir}/docs runner = ignore_env_name_mismatch -[testenv:docs-build] +[testenv:build-docs] description = Build sphinx documentation base = docs allowlist_externals = bash commands_pre = bash -c 'if [[ ! -e docs ]];then echo "No docs directory. Run `tox run -e sphinx-quickstart` to create one.;";return 1;fi' # "-W" is to treat warnings as errors -commands = sphinx-build {posargs:-b html} -W {tox_root}/docs {tox_root}/docs/_build +commands = sphinx-build {posargs:-b html} -W {tox_root}/docs {tox_root}/docs/_build/html -[testenv:docs-autobuild] +[testenv:autobuild-docs] description = Build documentation with an autoupdating server base = docs -commands = sphinx-autobuild {posargs:-b html --open-browser --port 8080} -W --watch {tox_root}/starcraft {tox_root}/docs {tox_root}/docs/_build +commands = sphinx-autobuild {posargs:-b html --open-browser --port 8080} -W --watch {tox_root}/craft_application {tox_root}/docs {tox_root}/docs/_build/html [testenv:lint-docs] description = Lint the documentation with sphinx-lint base = docs -commands = sphinx-lint --ignore docs/_build --max-line-length 160 -e all {posargs} docs/ +commands = sphinx-lint --ignore docs/_build/html --max-line-length 80 -e all {posargs} docs/ labels = lint