gifn-apply: move all the Python files into python/

...and adapt the paths in the various project and linter config files.

Change-Id: I9e3e06d07afaf39d08f5a9cffc3fbe0e84741827
diff --git a/tools/git-if-needed/python/config/ruff-base/pyproject.toml b/tools/git-if-needed/python/config/ruff-base/pyproject.toml
index d067c07..b9bd0ec 100644
--- a/tools/git-if-needed/python/config/ruff-base/pyproject.toml
+++ b/tools/git-if-needed/python/config/ruff-base/pyproject.toml
@@ -32,4 +32,4 @@
 
 [tool.ruff.per-file-ignores]
 # This is a test suite
-"python/tests/unit/*" = ["S101"]
+"tests/unit/*" = ["S101"]
diff --git a/tools/git-if-needed/python/pyproject.toml b/tools/git-if-needed/python/pyproject.toml
new file mode 100644
index 0000000..1c0dd26
--- /dev/null
+++ b/tools/git-if-needed/python/pyproject.toml
@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: StorPool <support@storpool.com>
+# SPDX-License-Identifier: BSD-2-Clause
+
+[build-system]
+requires = ["setuptools >= 61", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "gifn_apply"
+version = "0.1.0"
+description = "Functional tests for the git-if-needed tool"
+readme = "README.md"
+requires-python = ">= 3.8"
+
+[[project.authors]]
+name = "StorPool"
+email = "support@storpool.com"
+
+[project.scripts]
+gifn_apply = "gifn_apply.__main__:main"
+
+[tool.setuptools]
+zip-safe = true
+package-dir = {"" = "src"}
+packages = ["gifn_apply"]
+
+[tool.mypy]
+strict = true
+python_version = "3.8"
+
+[tool.test-stages]
+stages = ["@check and @quick and not @manual", "@check and not @manual", "@tests and not @manual"]
diff --git a/tools/git-if-needed/python/tox.ini b/tools/git-if-needed/python/tox.ini
new file mode 100644
index 0000000..a17f44c
--- /dev/null
+++ b/tools/git-if-needed/python/tox.ini
@@ -0,0 +1,86 @@
+# SPDX-FileCopyrightText: StorPool <support@storpool.com>
+# SPDX-License-Identifier: BSD-2-Clause
+
+[tox]
+minversion = 4.1
+envlist =
+  ruff
+  ruff-all
+  format
+  mypy
+  unit-tests
+  functional-cinder
+isolated_build = true
+
+[defs]
+pyfiles =
+  src/gifn_apply \
+  tests/unit
+
+[testenv:format]
+skip_install = True
+tags =
+  check
+deps =
+  -r requirements/ruff.txt
+commands =
+  ruff check --config config/ruff-base/pyproject.toml --select=D,I --diff -- {[defs]pyfiles}
+  ruff format --check --config config/ruff-base/pyproject.toml --diff -- {[defs]pyfiles}
+
+[testenv:reformat]
+skip_install = True
+tags =
+  format
+  manual
+deps =
+  -r requirements/ruff.txt
+commands =
+  ruff check --config config/ruff-base/pyproject.toml --select=D,I --fix -- {[defs]pyfiles}
+  ruff format --config config/ruff-base/pyproject.toml -- {[defs]pyfiles}
+
+[testenv:mypy]
+skip_install = True
+tags =
+  check
+deps =
+  -r requirements/test.txt
+  mypy >= 1, < 2
+commands =
+  mypy -- {[defs]pyfiles}
+
+[testenv:ruff]
+skip_install = True
+tags =
+  check
+  quick
+deps =
+  -r requirements/ruff.txt
+commands =
+  ruff check --config config/ruff-all/pyproject.toml -- {[defs]pyfiles}
+
+[testenv:unit-tests]
+tags =
+  tests
+deps =
+  -r requirements/test.txt
+commands =
+  pytest {posargs} tests/unit
+
+[testenv:reuse]
+skip_install = True
+tags =
+  check
+  quick
+deps =
+  reuse >= 2, < 3
+commands =
+  reuse --root={toxinidir}/.. lint
+
+[testenv:functional-cinder]
+tags =
+  tests
+setenv =
+  REPO_URL_OPENSTACK = {env:REPO_URL_OPENSTACK:https://github.com/openstack}
+commands =
+  gifn_apply -v -p {toxinidir}/../../../patches -P {toxinidir}/../sh/git-if-needed
+  gifn_apply -v -p {toxinidir}/../../../patches -P {toxinidir}/../sh/git-if-needed -s series.experimental