From f5f6c639aa8ecfe9df8bdb462263a003b378e3b9 Mon Sep 17 00:00:00 2001 From: Nicholas Bollweg Date: Mon, 10 Apr 2023 09:09:29 -0500 Subject: [PATCH] Preflight 1.3.0 (#114) --- .binder/environment.yml | 1 + .github/environment.yml | 1 + .github/pull_request_template.md | 49 ++++++++++++++++++ .github/workflows/badges.yml | 2 +- .github/workflows/ci.yml | 24 +++------ .yarnrc | 2 +- CONTRIBUTING.md | 45 ++++------------- demo/jupyter_lite_config.json | 3 +- docs/environment.yml | 1 + dodo.py | 64 +++++++++-------------- py_packages/ipydrawio-export/setup.cfg | 4 +- py_packages/ipydrawio-mathjax/setup.cfg | 4 +- py_packages/ipydrawio-widgets/setup.cfg | 4 +- py_packages/ipydrawio/setup.cfg | 4 +- pyproject.toml | 2 +- scripts/project.py | 67 ++++++++++++++----------- 16 files changed, 149 insertions(+), 128 deletions(-) create mode 100644 .github/pull_request_template.md diff --git a/.binder/environment.yml b/.binder/environment.yml index f4f7f2d..a2d5384 100644 --- a/.binder/environment.yml +++ b/.binder/environment.yml @@ -102,6 +102,7 @@ dependencies: - ssort # unit testing - pytest + - pytest-cov - pytest-console-scripts - pytest-html - pytest-jupyter-server diff --git a/.github/environment.yml b/.github/environment.yml index f44aa4e..904803e 100644 --- a/.github/environment.yml +++ b/.github/environment.yml @@ -50,6 +50,7 @@ dependencies: - ssort # unit testing - pytest + - pytest-cov - pytest-console-scripts - pytest-html - pytest-jupyter-server diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f9aee4d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,49 @@ + + +## References + + + + + +## Code changes + + + +## User-facing changes + + + + + +## Backwards-incompatible changes + + + +## Chores + +- [ ] ran `doit lint` +- [ ] updated `CHANGELOG.md` +- [ ] validated on binder +- [ ] validated on ReadTheDocs + + diff --git a/.github/workflows/badges.yml b/.github/workflows/badges.yml index 4b37f78..8887dac 100644 --- a/.github/workflows/badges.yml +++ b/.github/workflows/badges.yml @@ -45,5 +45,5 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: `Try this PR on [![](${LITE})](${RTD}) :arrow_left: ReadTheDocs or Binder :arrow_right: [![](${BND})](${BH})`, + body: `Try this PR on [![RTD](${LITE})](${RTD}) :arrow_left: ReadTheDocs or Binder :arrow_right: [![Binder](${BND})](${BH})`, }); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a38faa..4d33f59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: if: steps.cache-node-modules.outputs.cache-hit != 'true' id: cache-yarn-packages with: - path: .yarn-packages + path: ./build/.cache/.yarn-packages key: | ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }} restore-keys: | @@ -296,21 +296,13 @@ jobs: cd ../ipydrawio-mathjax codecov --root ../.. - - name: upload (utest) + - name: upload (reports) if: always() uses: actions/upload-artifact@v3 with: name: |- - ipydrawio-${{ github.run_number }}-utest-${{ matrix.os }}-${{ matrix.python-version }} - path: ./build/pytest - - - name: upload (atest) - if: always() - uses: actions/upload-artifact@v3 - with: - name: |- - ipydrawio-${{ github.run_number }}-atest-${{ matrix.os }}-${{matrix.python-version }} - path: ./build/atest + ipydrawio-${{ github.run_number }}-reports-${{ matrix.os }}-${{matrix.python-version }} + path: ./build/reports - name: Rename uncached conda packages shell: bash @@ -343,7 +335,7 @@ jobs: if: steps.cache-node-modules.outputs.cache-hit != 'true' id: cache-yarn-packages with: - path: .yarn-packages + path: ./build/.cache/.yarn-packages key: | ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }} restore-keys: | @@ -399,7 +391,7 @@ jobs: if: steps.cache-node-modules.outputs.cache-hit != 'true' id: cache-yarn-packages with: - path: .yarn-packages + path: ./build/.cache/.yarn-packages key: | ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }} restore-keys: | @@ -430,12 +422,12 @@ jobs: shell: bash -l {0} run: doit test:robot - - name: upload (atest) + - name: upload (reports) if: always() uses: actions/upload-artifact@v3 with: name: |- - ipydrawio-${{ github.run_number }}-atest-${{ matrix.os }}${{ matrix.python-version }} + ipydrawio-${{ github.run_number }}-reports-${{ matrix.os }}${{ matrix.python-version }} path: ./build/atest - name: upload (docs) diff --git a/.yarnrc b/.yarnrc index 9d4e33a..9e913c9 100644 --- a/.yarnrc +++ b/.yarnrc @@ -3,5 +3,5 @@ ignore-scripts true network-timeout "300000" prefer-offline true registry "https://registry.npmjs.org/" -yarn-offline-mirror "./.yarn-packages" +yarn-offline-mirror "./build/.cache/.yarn-packages" yarn-offline-mirror-pruning true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8ff195..e2d6576 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,11 +14,12 @@ ## Prerequisites -- `jupyterlab >=3,<4` -- `nodejs >=12` - `doit >=0.32` +- `jupyterlab >=3,<4` +- `nodejs >=18,<19` +- `python >=3.8` -### Recommended: conda +### Recommended: `mamba` - Get [Miniforge/Mambaforge](https://github.com/conda-forge/miniforge/releases) @@ -76,38 +77,12 @@ doit dist ## Releasing -- [ ] start a release issue with a checklist (maybe like this one) -- [ ] merge all outstanding PRs -- [ ] ensure the versions have been bumped (check with `doit test:integrity`) -- [ ] ensure the CHANGELOG is up-to-date - - [ ] move the new release to the top of the stack -- [ ] validate on binder -- [ ] validate on ReadTheDocs -- [ ] wait for a successful build of `master` -- [ ] download the `dist` archive and unpack somewhere (maybe a fresh `dist`) -- [ ] create a new release through the GitHub UI - - [ ] paste in the relevant CHANGELOG entries - - [ ] upload the artifacts -- [ ] actually upload to npm.com, pypi.org - ```bash - cd dist - twine upload ipydrawio* - npm login - npm publish deathbeds-ipydrawio-$VERSION.tgz - npm publish deathbeds-ipydrawio-jupyter-templates-$VERSION.tgz - npm publish deathbeds-ipydrawio-notebook-$VERSION.tgz - npm publish deathbeds-ipydrawio-pdf-$VERSION.tgz - npm publish deathbeds-ipydrawio-webpack-$OTHER_VERSION.tgz - npm logout - ``` -- [ ] postmortem - - [ ] handle `conda-forge` feedstock tasks - - [ ] validate on binder via simplest-possible gists - - [ ] activate the version on ReadTheDocs - - [ ] bump to next development version - - [ ] update release procedures +- Start a [release] issue on GitHub + - Follow the checklist -``` +[release]: https://github.com/deathbeds/ipydrawio/issues/new?template=release.md + + diff --git a/demo/jupyter_lite_config.json b/demo/jupyter_lite_config.json index dd86925..ac5a729 100644 --- a/demo/jupyter_lite_config.json +++ b/demo/jupyter_lite_config.json @@ -12,7 +12,8 @@ "ignore_sys_prefix": true, "lite_dir": ".", "output_archive": "../build/demo/ipydrawio-lite-1.3.0.tgz", - "output_dir": "../build/demo" + "output_dir": "../build/demo", + "cache_dir": "../build/.cache/.lite" }, "PipliteAddon": { "piplite_urls": [ diff --git a/docs/environment.yml b/docs/environment.yml index baa4e87..55283c3 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -73,6 +73,7 @@ dependencies: - ssort # unit testing - pytest + - pytest-cov - pytest-console-scripts - pytest-html - pytest-jupyter-server diff --git a/dodo.py b/dodo.py index 98e2bd3..4ac12e0 100644 --- a/dodo.py +++ b/dodo.py @@ -942,14 +942,10 @@ def task_provision(): ) -def _pytest(setup_py, pycov_args, pytest_args): +def _pytest(setup_py, pytest_args): return CmdAction( [ *P.PYM, - "coverage", - "run", - *pycov_args, - "-m", "pytest", *P.PYTEST_ARGS, *pytest_args, @@ -963,30 +959,6 @@ def _pytest(setup_py, pycov_args, pytest_args): ) -def _pycov_combine(setup_py): - return CmdAction( - [*P.PYM, "coverage", "combine"], - shell=False, - cwd=str(setup_py.parent), - ) - - -def _pycov_report(setup_py): - return CmdAction( - [*P.PYM, "coverage", "report", "--skip-covered", "--show-missing"], - shell=False, - cwd=str(setup_py.parent), - ) - - -def _pycov_html(setup_py, *pycov_html_args): - return CmdAction( - [*P.PYM, "coverage", "html", *pycov_html_args], - shell=False, - cwd=str(setup_py.parent), - ) - - def task_test(): """Run tests.""" if not P.TESTING_IN_CI: @@ -1006,24 +978,39 @@ def task_test(): P.SCRIPTS / "integrity.py", ], "actions": [ - ["python", "-m", "pytest", "--pyargs", "scripts.integrity", "-vv"], + [ + *P.PYM, + "pytest", + "--pyargs", + "scripts.integrity", + "-vv", + *("-o", f"""cache_dir={P.CACHE / ".pytest.integrity"}"""), + ], ], }, P.OK_INTEGRITY, ) for pkg, setup in P.PY_SETUP.items(): - html = P.BUILD / f"pytest/{pkg}/test.html" - htmlcov = P.BUILD / f"pytest/{pkg}/htmlcov" + report_dir = P.REPORTS / "pytest" / pkg + html = report_dir / "pytest.html" + cov_index = report_dir / "htmlcov" / "index.html" + cache_dir = P.CACHE / f".pytest.{pkg}" pytest_args = [ "-vv", "--tb=long", + *("-o", f"cache_dir={cache_dir}"), + # subs + "--script-launch-mode=subprocess", + # report f"--html={html}", "--self-contained-html", - "--script-launch-mode=subprocess", + # cov + "--cov-context=test", + f"""--cov={pkg.replace("-", "_")}""", + f"--cov-report=html:{cov_index.parent}", + "--cov-branch", ] - pycov_args = [] - pycov_html_args = [f"--directory={htmlcov.parent}"] if pkg == P.IPD.name: pytest_args += ["-n", "auto"] @@ -1041,12 +1028,9 @@ def task_test(): ], "actions": [ (P.delete_some, [html]), - _pytest(setup, pycov_args, pytest_args), - _pycov_combine(setup), - _pycov_html(setup, *pycov_html_args), - _pycov_report(setup), + _pytest(setup, pytest_args), ], - "targets": [html], + "targets": [html, cov_index], }, P.OK_PYTEST[pkg], ) diff --git a/py_packages/ipydrawio-export/setup.cfg b/py_packages/ipydrawio-export/setup.cfg index ef8d5df..c3cb5a9 100644 --- a/py_packages/ipydrawio-export/setup.cfg +++ b/py_packages/ipydrawio-export/setup.cfg @@ -39,7 +39,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -85,3 +84,6 @@ source_pkgs = ipydrawio_export concurrency = multiprocessing parallel = True + +[coverage:html] +show_contexts = True diff --git a/py_packages/ipydrawio-mathjax/setup.cfg b/py_packages/ipydrawio-mathjax/setup.cfg index ae8640b..7ff5612 100644 --- a/py_packages/ipydrawio-mathjax/setup.cfg +++ b/py_packages/ipydrawio-mathjax/setup.cfg @@ -39,7 +39,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -73,3 +72,6 @@ source_pkgs = ipydrawio_mathjax concurrency = multiprocessing parallel = True + +[coverage:html] +show_contexts = True diff --git a/py_packages/ipydrawio-widgets/setup.cfg b/py_packages/ipydrawio-widgets/setup.cfg index 1b05a69..214e2dd 100644 --- a/py_packages/ipydrawio-widgets/setup.cfg +++ b/py_packages/ipydrawio-widgets/setup.cfg @@ -37,7 +37,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -72,3 +71,6 @@ source_pkgs = ipydrawio_widgets concurrency = multiprocessing parallel = True + +[coverage:html] +show_contexts = True diff --git a/py_packages/ipydrawio/setup.cfg b/py_packages/ipydrawio/setup.cfg index 3239862..01f8f29 100644 --- a/py_packages/ipydrawio/setup.cfg +++ b/py_packages/ipydrawio/setup.cfg @@ -40,7 +40,6 @@ classifiers = License :: OSI Approved :: Apache Software License Programming Language :: Python Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -91,3 +90,6 @@ source_pkgs = ipydrawio concurrency = multiprocessing parallel = True + +[coverage:html] +show_contexts = True diff --git a/pyproject.toml b/pyproject.toml index 4d00bd7..bab3d45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.ruff] fix = true -cache-dir = "build/.cache/ruff" +cache-dir = "build/.cache/.ruff" ignore = [ "BLE001", "E501", diff --git a/scripts/project.py b/scripts/project.py index 32e925c..95f71fc 100644 --- a/scripts/project.py +++ b/scripts/project.py @@ -136,15 +136,19 @@ YARN_INTEGRITY = NODE_MODULES / ".yarn-integrity" YARN_LOCK = ROOT / "yarn.lock" DODO = ROOT / "dodo.py" BUILD = ROOT / "build" +REPORTS = BUILD / "reports" +OK = BUILD / "ok" DIST = ROOT / "dist" DOCS = ROOT / "docs" README = ROOT / "README.md" CHANGELOG = ROOT / "CHANGELOG.md" +CACHE = BUILD / ".cache" # external URLs # archive.org template CACHE_EPOCH = 0 -HTTP_CACHE = BUILD / ".requests-cache" +HTTP_CACHE = CACHE / ".requests-cache" +BLACK_CACHE_DIR = CACHE / ".black" def A_O(archive_id, url, cache_bust=CACHE_EPOCH): @@ -200,7 +204,7 @@ EXAMPLE_IPYNB = _clean(EXAMPLES.rglob("*.ipynb")) DIST_NBHTML = DIST / "nbsmoke" ATEST = ROOT / "atest" ATEST_DIO = _clean(ATEST.rglob("*.dio"), ATEST.rglob("*.dio.svg")) -ATEST_OUT = BUILD / "atest" +ATEST_OUT = REPORTS / "atest" ATEST_OUT_XML = "output.xml" ATEST_TEMPLATES = [*ATEST.rglob("*.robot.j2")] @@ -365,7 +369,7 @@ JS_PKG_PACK = { for k, v in JS_TSBUILDINFO.items() if not k.startswith("_") ] -OK_PYSETUP = {k: BUILD / f"pysetup.{k}.ok" for k, v in PY_SETUP.items()} +OK_PYSETUP = {k: OK / f"pysetup.{k}.ok" for k, v in PY_SETUP.items()} PY_SETUP_DEPS = { IPD: lambda: [OK_PYSETUP["ipydrawio-widgets"]], @@ -557,32 +561,32 @@ JS_PKG_PACK[IPDM.name][0] += [IPDWP_IGNORE, IPDWP_APP, *ALL_IPDM_JS, IPDM_STARTU IPYDRAWIO_DATA_DIR = Path(sys.prefix) / "share/jupyter/ipydrawio_export" # built files -OK_PIP_CHECK = BUILD / "pip.check.ok" -OK_INTEGRITY = BUILD / "integrity.ok" -OK_SUBMODULES = BUILD / "submodules.ok" -OK_BLACK = BUILD / "black.ok" -OK_BLACK_JUPYTER = BUILD / "black.jupyter.ok" -OK_NBQA_RUFF = BUILD / "nbqa.ruff.ok" -OK_RUFF = BUILD / "ruff.ok" -OK_FLAKE8 = BUILD / "flake8.ok" -OK_SSORT = BUILD / "ssort.ok" -OK_LINT = BUILD / "lint.ok" -OK_ROBOTIDY = BUILD / "robot.tidy.ok" -OK_PRETTIER = BUILD / "prettier.ok" -OK_ESLINT = BUILD / "eslint.ok" -OK_JS_BUILD_PRE = BUILD / "js.build.pre.ok" -OK_JS_BUILD = BUILD / "js.build.ok" -OK_PYTEST = {k: BUILD / f"pytest.{k}.ok" for k, v in PY_SETUP.items()} -OK_SERVEREXT = {k: BUILD / f"serverext.{k}.ok" for k, v in SERVER_EXT.items()} -OK_PROVISION = BUILD / "provision.ok" -OK_ROBOT_DRYRUN = BUILD / "robot.dryrun.ok" -OK_ROBOCOP = BUILD / "robot.robocop.ok" -OK_DIOLINT = BUILD / "dio.lint.ok" -OK_ATEST = BUILD / "atest.ok" -OK_CONDA_TEST = BUILD / "conda-build.test.ok" -OK_LINK_CHECK = BUILD / "pytest-check-links.ok" +OK_PIP_CHECK = OK / "pip.check.ok" +OK_INTEGRITY = OK / "integrity.ok" +OK_SUBMODULES = OK / "submodules.ok" +OK_BLACK = OK / "black.ok" +OK_BLACK_JUPYTER = OK / "black.jupyter.ok" +OK_NBQA_RUFF = OK / "nbqa.ruff.ok" +OK_RUFF = OK / "ruff.ok" +OK_FLAKE8 = OK / "flake8.ok" +OK_SSORT = OK / "ssort.ok" +OK_LINT = OK / "lint.ok" +OK_ROBOTIDY = OK / "robot.tidy.ok" +OK_PRETTIER = OK / "prettier.ok" +OK_ESLINT = OK / "eslint.ok" +OK_JS_BUILD_PRE = OK / "js.build.pre.ok" +OK_JS_BUILD = OK / "js.build.ok" +OK_PYTEST = {k: OK / f"pytest.{k}.ok" for k, v in PY_SETUP.items()} +OK_SERVEREXT = {k: OK / f"serverext.{k}.ok" for k, v in SERVER_EXT.items()} +OK_PROVISION = OK / "provision.ok" +OK_ROBOT_DRYRUN = OK / "robot.dryrun.ok" +OK_ROBOCOP = OK / "robot.robocop.ok" +OK_DIOLINT = OK / "dio.lint.ok" +OK_ATEST = OK / "atest.ok" +OK_CONDA_TEST = OK / "conda-build.test.ok" +OK_LINK_CHECK = OK / "pytest-check-links.ok" -OK_EXT_BUILD = {k: BUILD / f"ext.build.{k}.ok" for k in JS_LABEXT_PY_HOST} +OK_EXT_BUILD = {k: OK / f"ext.build.{k}.ok" for k in JS_LABEXT_PY_HOST} PY_TEST_DEP.setdefault("ipydrawio-export", []).append(OK_PROVISION) @@ -829,7 +833,11 @@ def _ok(task, ok): task["actions"] = [ lambda: [ok.exists() and ok.unlink(), True][-1], *task["actions"], - lambda: [ok.parent.mkdir(exist_ok=True), ok.write_text("ok", **ENC), True][-1], + lambda: [ + ok.parent.mkdir(exist_ok=True, parents=True), + ok.write_text("ok", **ENC), + True, + ][-1], ] return task @@ -1068,4 +1076,5 @@ os.environ.update( JUPYTER_PLATFORM_DIRS="1", PYDEVD_DISABLE_FILE_VALIDATION="1", IPYDRAWIO_DATA_DIR=str(IPYDRAWIO_DATA_DIR), + BLACK_CACHE_DIR=str(BLACK_CACHE_DIR), )