# https://taskfile.dev/usage/ # https://pkg.go.dev/text/template # https://go-task.github.io/slim-sprig/ version: "3" vars: TASKFILE_DIR: sh: pwd POETRY: poetry # The prefix to use when running dev commands RUN_PREFIX: "{{.POETRY}} run" # The python to use for running in the venv VENV_PYTHON: "{{.RUN_PREFIX}} python" # The python interpreter to use. PYTHON: python # Truthish values ("true", "1", etc.) results in java being installed as a # system dependency. INSTALL_SYSTEM_DEPS_JAVA: "false" # Truthish values ("true", "1", etc.) results in extras being installed with # pip. INSTALL_EXTRAS: "false" # Truthish values ("true", "1", etc.) results in extensive tests being ran and # dependencies for extensive tests being installed. EXTENSIVE: "false" # The python version for which tox should run, empty string does not restrict # python versions. TOX_PYTHON_VERSION: "" TEST_HARNESS: '{{if (and (mustFromJson .EXTENSIVE) (not (eq OS "windows")))}}./with-fuseki.sh{{end}} ' # Truthish values ("true", "1", etc.) results in github specific things being # done. WITH_GITHUB_ACTIONS: "false" # Truthish values ("true", "1", etc.) results in coverage being generated for # relevant commands. WITH_COVERAGE: "false" PIP_COMPILE: pip-compile DOCKER: docker OCI_REFERENCE: ghcr.io/rdflib/rdflib tasks: install:system-deps: desc: Install system dependencies cmds: - echo "OS = {{OS}}" - echo "ARCH = {{ARCH}}" - | {{if (and (mustFromJson .EXTENSIVE) (eq OS "linux"))}} if type apt-get >/dev/null 2>&1 then sudo apt-get install -y libdb-dev elif type dnf >/dev/null 2>&1 then sudo dnf install -y libdb-devel fi {{else if (and (mustFromJson .EXTENSIVE) (eq OS "darwin"))}} brew install berkeley-db@4 {{end}} install:tox: desc: Install tox cmds: - "{{.PYTHON}} -m pip install tox {{if (mustFromJson .WITH_GITHUB_ACTIONS)}}tox-gh-actions{{end}}" poetry:configure: desc: Configure the environment for development with poetry cmds: - | {{if .POETRY_PYTHON}} {{.POETRY}} env use {{.POETRY_PYTHON}} {{end}} {{.POETRY}} install {{if (or (mustFromJson .INSTALL_EXTRAS) (mustFromJson .EXTENSIVE))}} --all-extras{{end}} {{.CLI_ARGS}} configure: desc: Configure the environment for development cmds: - task: venv:install venv:install: desc: Create and install a venv cmds: - task: poetry:configure venv:clean: desc: Clean the virtual environment cmds: - "{{.POETRY}} env remove --all {{.CLI_ARGS}}" venv:run: desc: Run a command inside the venv cmds: - cmd: | {{.RUN_PREFIX}} {{.CLI_ARGS}} run: desc: Run a command. If WITH_VENV is truthish, the command will be run inside the virtual environment. cmds: - task: venv:run tox: desc: Run tox cmds: - echo "TOXENV=${TOXENV}" - | {{if .TOX_PYTEST_ARGS}}TOX_PYTEST_ARGS={{shellQuote .TOX_PYTEST_ARGS}}{{end}} \ {{if .TOX_JUNIT_XML_PREFIX}}TOX_JUNIT_XML_PREFIX={{shellQuote .TOX_JUNIT_XML_PREFIX}}{{end}} \ {{if .COVERAGE_FILE}}COVERAGE_FILE={{shellQuote .COVERAGE_FILE}}{{end}} \ {{.TEST_HARNESS}} \ {{.PYTHON | shellQuote}} \ -m tox \ {{.CLI_ARGS}} env: TOXENV: '{{if .TOX_PYTHON_VERSION}}py{{mustRegexReplaceAll "^([0-9]+)[.]([0-9]+).*" .TOX_PYTHON_VERSION "${1}${2}"}}{{if (mustFromJson .EXTENSIVE)}}-extensive{{end}}{{.TOXENV_SUFFIX | default ""}}{{end}}' test: desc: Run tests cmds: - '{{.TEST_HARNESS}}{{.RUN_PREFIX}} pytest {{if (mustFromJson .WITH_COVERAGE)}}--cov --cov-report={{end}} {{.CLI_ARGS}}' flake8: desc: Run flake8 cmds: - | if {{.VENV_PYTHON}} -c 'import importlib.util; exit(0 if importlib.util.find_spec("flakeheaven") is not None else 1)' then 1>&2 echo "running flakeheaven" {{.VENV_PYTHON}} -m flakeheaven lint {{.CLI_ARGS}} else 1>&2 echo "skipping flakeheaven as it is not installed, likely because python version is older than 3.8" fi black: desc: Run black cmds: - '{{.VENV_PYTHON}} -m black {{if (mustFromJson (.CHECK | default "false"))}}--check --diff {{end}}{{.CLI_ARGS | default "."}}' isort: desc: Run isort cmds: - '{{.VENV_PYTHON}} -m isort {{if (mustFromJson (.CHECK | default "false"))}}--check --diff {{end}}{{.CLI_ARGS | default "."}}' mypy: desc: Run mypy cmds: - "{{.VENV_PYTHON}} -m mypy --show-error-context --show-error-codes {{.CLI_ARGS}}" lint:fix: desc: Fix auto-fixable linting errors cmds: - task: isort - task: black lint: desc: Perform linting cmds: - task: isort vars: { CHECK: true } - task: black vars: { CHECK: true } - task: flake8 validate:static: desc: Perform static validation cmds: - task: lint - task: mypy validate:fix: desc: Fix auto-fixable validation errors. cmds: - task: lint:fix validate: desc: Perform all validation cmds: - task: validate:static - task: test docs:clean: desc: Clean generated documentation cmds: - task: _rimraf vars: { RIMRAF_TARGET: "docs/_build/" } docs: desc: Build documentation cmds: - echo "PYTHONPATH=${PYTHONPATH}" - "{{.VENV_PYTHON}} -m sphinx.cmd.build -T -W -b html -d docs/_build/doctree docs docs/_build/html {{.CLI_ARGS}}" docs:live-server: desc: Run a live server on generated docs cmds: - 'echo "NOTE: Docs must be built for this to work"' - npx -p live-server live-server docs/_build/html/ {{.CLI_ARGS}} default: desc: Run validate cmds: - task: validate clean:mypy: desc: Clean mypy cache cmds: - task: _rimraf vars: { RIMRAF_TARGET: ".mypy_cache" } - task: clean:tox:mypy clean:tox: desc: Clean tox environments cmds: - task: _rimraf vars: { RIMRAF_TARGET: ".tox" } clean:tox:mypy: desc: Clean mypy cache inside tox environments cmds: - task: _rimraf vars: { RIMRAF_TARGET: ".tox/*/.mypy_cache/" } clean: desc: Clean everything cmds: - task: docs:clean - task: clean:tox - task: clean:mypy - task: venv:clean - task: _rimraf vars: { RIMRAF_TARGET: ".var/devcontainer" } - task: _rimraf vars: { RIMRAF_TARGET: "var/test-sdist" } test:data:fetch: desc: Fetch test data. cmds: - "{{.VENV_PYTHON}} test/data/fetcher.py {{.CLI_ARGS}}" pre-commit:install: desc: Install pre-commit hooks cmds: - pre-commit install {{.CLI_ARGS}} pre-commit:run: desc: Run pre-commit cmds: - pre-commit run {{.CLI_ARGS}} pre-commit:run:all-files: desc: Run pre-commit on all files cmds: - pre-commit run --all-files {{.CLI_ARGS}} gha:validate: desc: GitHub Actions Validation Workflow env: COVERALLS_PARALLEL: true COVERALLS_FLAG_NAME: "{{.OS}}-{{.TOX_PYTHON_VERSION}}{{.MATRIX_SUFFIX}}" COVERALLS_SERVICE_NAME: '{{.COVERALLS_SERVICE_NAME | default (env "COVERALLS_SERVICE_NAME") | default "github"}}' cmds: - task: install:system-deps - task: install:tox vars: WITH_GITHUB_ACTIONS: true - cmd: "{{.PYTHON}} -m pip install coveralls" - task: tox vars: COVERAGE_FILE: ".coverage" - cmd: coveralls gha:flake8: desc: GitHub Actions flake8 workflow cmds: - task: poetry:configure vars: CLI_ARGS: --no-root --only=flake8 - task: flake8 cmd:rdfpipe: desc: Run rdfpipe cmds: - cmd: "{{.VENV_PYTHON}} -m rdflib.tools.rdfpipe {{.CLI_ARGS}}" pip-compile: cmds: - cmd: "{{.PIP_COMPILE}} --quiet --annotate --emit-options --resolver=backtracking {{.CLI_ARGS}}" docker:prepare: cmds: - task: pip-compile vars: { CLI_ARGS: "docker/latest/requirements.in" } docker:unstable: desc: ... cmds: - cmd: | # fetch for caching ... {{.DOCKER}} image pull {{.OCI_REFERENCE}}:unstable || : set -eo pipefail mkdir -vp var {{.POETRY}} export -o var/requirements.txt pipx run --spec=build build --wheel {{.DOCKER}} buildx build \ --cache-to=type=inline \ --cache-from=type=registry,ref={{.OCI_REFERENCE}}:unstable \ --tag {{.OCI_REFERENCE}}:unstable \ --progress plain \ -f docker/unstable/Dockerfile \ {{.DOCKER_BUILD_ARGS}} \ . if {{.DOCKER_PUSH | default "false"}} then {{.DOCKER}} image push {{.OCI_REFERENCE}}:unstable fi docker:latest: desc: ... cmds: - cmd: | # fetch for caching ... {{.DOCKER}} image pull {{.OCI_REFERENCE}}:latest || : set -eo pipefail {{.DOCKER}} buildx build \ --cache-to=type=inline \ --cache-from=type=registry,ref={{.OCI_REFERENCE}}:latest \ --tag {{.OCI_REFERENCE}}:latest \ --progress plain \ -f docker/latest/Dockerfile \ {{.DOCKER_BUILD_ARGS}} \ . _latest_rdflib_version=$({{.DOCKER}} run --entrypoint= {{.OCI_REFERENCE}}:latest bash -c 'pip show rdflib | sed -n "s/^Version: //gp"') echo "_latest_rdflib_version=${_latest_rdflib_version}" {{.DOCKER}} image tag {{.OCI_REFERENCE}}:latest {{.OCI_REFERENCE}}:${_latest_rdflib_version} if {{.DOCKER_PUSH | default "false"}} then {{.DOCKER}} image push {{.OCI_REFERENCE}}:latest {{.DOCKER}} image push {{.OCI_REFERENCE}}:${_latest_rdflib_version} fi docs:build-diagrams: desc: Build documentation diagrams cmds: - cmd: | shopt -s globstar; for plantuml_file in ./**/*.plantuml do cat "${plantuml_file}" \ | docker run --rm -i plantuml/plantuml -tsvg -pipe \ > "${plantuml_file%.*}.svg" done test:sdist: desc: Run tests on the sdist artifact cmds: - task: _rimraf vars: { RIMRAF_TARGET: "dist" } - task: _rimraf vars: { RIMRAF_TARGET: "var/test-sdist" } - poetry build - python -c 'import tarfile, glob; tarfile.open(glob.glob("dist/*.tar.gz")[0]).extractall("var/test-sdist")' - | cd var/test-sdist/rdflib-* poetry install poetry run mypy --show-error-context --show-error-codes -p rdflib poetry run sphinx-build -T -W -b html -d docs/_build/doctree docs docs/_build/html poetry run pytest test:no_internet: desc: Run tests without internet access cmds: - | {{.TEST_HARNESS}}{{.RUN_PREFIX}} firejail --net=none -- pytest -m "not webtest" {{.CLI_ARGS}} _rimraf: # This task is a utility task for recursively removing directories, it is # similar to rm -rf but not identical and it should work wherever there is # a python interpreter. The name is inspired by # . - cmd: | {{.PYTHON}} -c ' from pathlib import Path; import sys, shutil; for path in sys.argv[1:]: if Path(path).exists(): sys.stderr.write(f"removing {path}\n") shutil.rmtree(path, ignore_errors=True) ' {{.RIMRAF_TARGET}}