Add the gifn-apply test tool

Add a tool that checks out the repositories mentioned in
a git-if-needed patch series, runs gif-it-needed, and performs
some checks on its operation. This tool will eventually be used in
a Zuul test job for this repository.

Change-Id: Id02fb7c21f5ab34d9639bf845fcc3961d929b13b
diff --git a/tools/git-if-needed/tox.ini b/tools/git-if-needed/tox.ini
new file mode 100644
index 0000000..fac9bfb
--- /dev/null
+++ b/tools/git-if-needed/tox.ini
@@ -0,0 +1,102 @@
+# SPDX-FileCopyrightText: StorPool <support@storpool.com>
+# SPDX-License-Identifier: BSD-2-Clause
+
+[tox]
+envlist =
+  ruff
+  ruff-all
+  black
+  pep8
+  mypy
+  pylint
+  unit-tests
+  functional-cinder
+isolated_build = true
+
+[defs]
+pyfiles =
+  python/gifn_apply
+  python/unit_tests
+
+[testenv:black]
+skip_install = True
+tags =
+  check
+deps =
+  black >= 23, < 24
+commands =
+  black --check -- {[defs]pyfiles}
+
+[testenv:black-reformat]
+skip_install = True
+tags =
+  format
+  manual
+deps =
+  black >= 23, < 24
+commands =
+  black -- {[defs]pyfiles}
+
+[testenv:pep8]
+skip_install = True
+tags =
+  check
+deps =
+  flake8 >= 6, < 7
+commands =
+  flake8 -- {[defs]pyfiles}
+
+[testenv:mypy]
+skip_install = True
+tags =
+  check
+deps =
+  -r python/requirements/test.txt
+  mypy >= 1, < 2
+commands =
+  mypy -- {[defs]pyfiles}
+
+[testenv:pylint]
+skip_install = True
+tags =
+  check
+deps =
+  -r python/requirements/test.txt
+  pylint >= 2.16, < 2.17
+commands =
+  pylint -- {[defs]pyfiles}
+
+[testenv:ruff]
+skip_install = True
+tags =
+  check
+deps =
+  ruff >= 0.0.253, < 0.1
+commands =
+  ruff check --config python/config/ruff-most/pyproject.toml -- {[defs]pyfiles}
+
+[testenv:ruff-all]
+skip_install = True
+tags =
+  check
+deps =
+  ruff == 0.0.253
+commands =
+  ruff check --config python/config/ruff-all/pyproject.toml -- {[defs]pyfiles}
+
+[testenv:unit-tests]
+tags =
+  tests
+deps =
+  -r python/requirements/test.txt
+commands =
+  pytest {posargs} python/unit_tests
+
+[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