You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by tv...@apache.org on 2022/04/05 10:04:42 UTC
[buildstream-plugins] 27/49: tests/sources/git.py: Adding tests for git source
This is an automated email from the ASF dual-hosted git repository.
tvb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/buildstream-plugins.git
commit ddeceebc6128c8b6cc5a06ab15a703724f7fc096
Author: Tristan van Berkom <tr...@codethink.co.uk>
AuthorDate: Mon Mar 21 14:44:23 2022 +0900
tests/sources/git.py: Adding tests for git source
---
tests/sources/git.py | 1143 ++++++++++++++++++++
tests/sources/git/project-override/project.conf | 12 +
.../git/project-override/repofiles/file.txt | 1 +
.../git/project-override/subrepofiles/ponyfile.txt | 1 +
.../template/inconsistent-submodule/.gitmodules | 3 +
.../git/template/othersubrepofiles/unicornfile.txt | 1 +
tests/sources/git/template/project.conf | 3 +
tests/sources/git/template/repofiles/file.txt | 1 +
.../sources/git/template/subrepofiles/ponyfile.txt | 1 +
9 files changed, 1166 insertions(+)
diff --git a/tests/sources/git.py b/tests/sources/git.py
new file mode 100644
index 0000000..beab0e6
--- /dev/null
+++ b/tests/sources/git.py
@@ -0,0 +1,1143 @@
+#
+# Copyright (C) 2018 Codethink Limited
+# Copyright (C) 2018 Bloomberg Finance LP
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Authors: Tristan Van Berkom <tr...@codethink.co.uk>
+# Jonathan Maw <jo...@codethink.co.uk>
+# William Salmon <wi...@codethink.co.uk>
+#
+
+# Pylint doesn't play well with fixtures and dependency injection from pytest
+# pylint: disable=redefined-outer-name
+
+import os
+import subprocess
+import shutil
+
+import pytest
+
+from buildstream import Node
+from buildstream.exceptions import ErrorDomain
+from buildstream.plugin import CoreWarnings
+from buildstream._testing import cli # pylint: disable=unused-import
+from buildstream._testing import generate_project, generate_element, load_yaml
+from buildstream._testing import create_repo
+
+from tests.testutils.site import HAVE_GIT, HAVE_OLD_GIT
+
+DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "git",)
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_fetch_bad_ref(cli, tmpdir, datafiles):
+ project = str(datafiles)
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Write out our test target with a bad ref
+ element = {"kind": "import", "sources": [repo.source_config(ref="5")]}
+ generate_element(project, "target.bst", element)
+
+ # Assert that fetch raises an error here
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.SOURCE, None)
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.skipif(HAVE_OLD_GIT, reason="old git cannot clone a shallow repo to stage the source")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_fetch_shallow(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ workspacedir = os.path.join(str(tmpdir), "workspace")
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+ first_commit = repo.latest_commit()
+ repo.add_commit()
+ repo.add_tag("tag")
+
+ ref = "tag-0-g" + repo.latest_commit()
+
+ element = {"kind": "import", "sources": [repo.source_config(ref=ref)]}
+ generate_element(project, "target.bst", element)
+
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["workspace", "open", "--directory", workspacedir, "target.bst"])
+ result.assert_success()
+
+ assert subprocess.call(["git", "show", "tag"], cwd=workspacedir) == 0
+ assert subprocess.call(["git", "show", first_commit], cwd=workspacedir) != 0
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_checkout(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config(ref=ref)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out both files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_recursive_submodule_fetch_checkout(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create a submodule from the 'othersubrepofiles' subdir
+ subsubrepo = create_repo("git", str(tmpdir), "subsubrepo")
+ subsubrepo.create(os.path.join(project, "othersubrepofiles"))
+
+ # Create another submodule from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Configure submodules
+ subrepo.add_submodule("subdir", "file://" + subsubrepo.repo)
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config(ref=ref)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out all files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subdir", "subdir", "unicornfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_source_enable_explicit(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config_extra(ref=ref, checkout_submodules=True)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out both files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_source_disable(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config_extra(ref=ref, checkout_submodules=False)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out both files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert not os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_submodule_does_override(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo, checkout=True)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config_extra(ref=ref, checkout_submodules=False)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out both files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_submodule_individual_checkout(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create another submodule from the 'othersubrepofiles' subdir
+ other_subrepo = create_repo("git", str(tmpdir), "othersubrepo")
+ other_subrepo.create(os.path.join(project, "othersubrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ repo.add_submodule("subdir", "file://" + subrepo.repo, checkout=False)
+ ref = repo.add_submodule("othersubdir", "file://" + other_subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config_extra(ref=ref, checkout_submodules=True)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert not os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "othersubdir", "unicornfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_fetch_submodule_individual_checkout_explicit(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create another submodule from the 'othersubrepofiles' subdir
+ other_subrepo = create_repo("git", str(tmpdir), "othersubrepo")
+ other_subrepo.create(os.path.join(project, "othersubrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ repo.add_submodule("subdir", "file://" + subrepo.repo, checkout=False)
+ ref = repo.add_submodule("othersubdir", "file://" + other_subrepo.repo, checkout=True)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config_extra(ref=ref, checkout_submodules=True)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert not os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+ assert os.path.exists(os.path.join(checkoutdir, "othersubdir", "unicornfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "project-override"))
+def test_submodule_fetch_project_override(cli, tmpdir, datafiles):
+ project = str(datafiles)
+ checkoutdir = os.path.join(str(tmpdir), "checkout")
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config(ref=ref)]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch, build, checkout
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkoutdir])
+ result.assert_success()
+
+ # Assert we checked out both files at their expected location
+ assert os.path.exists(os.path.join(checkoutdir, "file.txt"))
+ assert not os.path.exists(os.path.join(checkoutdir, "subdir", "ponyfile.txt"))
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_track_ignore_inconsistent(cli, tmpdir, datafiles):
+ project = str(datafiles)
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ ref = repo.create(os.path.join(project, "repofiles"))
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config(ref=ref)]}
+ generate_element(project, "target.bst", element)
+
+ # Now add a .gitmodules file with an inconsistent submodule,
+ # we are calling this inconsistent because the file was created
+ # but `git submodule add` was never called, so there is no reference
+ # associated to the submodule.
+ #
+ repo.add_file(os.path.join(project, "inconsistent-submodule", ".gitmodules"))
+
+ # Fetch should work, we're not yet at the offending ref
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+
+ # Track to update to the offending commit
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+
+ # Fetch after track will encounter an inconsistent submodule without any ref
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+
+ # Assert that we are just fine without it, and emit a warning to the user.
+ assert "Ignoring inconsistent submodule" in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_submodule_track_no_ref_or_track(cli, tmpdir, datafiles):
+ project = str(datafiles)
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Write out our test target
+ gitsource = repo.source_config(ref=None)
+ gitsource.pop("track")
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ # Track will encounter an inconsistent submodule without any ref
+ result = cli.run(project=project, args=["show", "target.bst"])
+ result.assert_main_error(ErrorDomain.SOURCE, "missing-track-and-ref")
+ result.assert_task_error(None, None)
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("fail", ["warn", "error"])
+def test_ref_not_in_track(cli, tmpdir, datafiles, fail):
+ project = str(datafiles)
+
+ # Make the warning an error if we're testing errors
+ if fail == "error":
+ generate_project(project, config={"fatal-warnings": [CoreWarnings.REF_NOT_IN_TRACK]})
+
+ # Create the repo from 'repofiles', create a branch without latest commit
+ repo = create_repo("git", str(tmpdir))
+ ref = repo.create(os.path.join(project, "repofiles"))
+
+ gitsource = repo.source_config(ref=ref)
+
+ # Overwrite the track value to the added branch
+ gitsource["track"] = "foo"
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+
+ # Assert a warning or an error depending on what we're checking
+ if fail == "error":
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.PLUGIN, CoreWarnings.REF_NOT_IN_TRACK)
+ else:
+ result.assert_success()
+ assert "ref-not-in-track" in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("fail", ["warn", "error"])
+def test_unlisted_submodule(cli, tmpdir, datafiles, fail):
+ project = str(datafiles)
+
+ # Make the warning an error if we're testing errors
+ if fail == "error":
+ generate_project(project, config={"fatal-warnings": ["git:unlisted-submodule"]})
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Create the source, and delete the explicit configuration
+ # of the submodules.
+ #
+ # We expect this to cause an unlisted submodule warning
+ # after the source has been fetched.
+ #
+ gitsource = repo.source_config(ref=ref)
+ del gitsource["submodules"]
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ # The warning or error is reported during fetch. There should be no
+ # error with `bst show`.
+ result = cli.run(project=project, args=["show", "target.bst"])
+ result.assert_success()
+ assert "git:unlisted-submodule" not in result.stderr
+
+ # We will notice this directly in fetch, as it will try to fetch
+ # the submodules it discovers as a result of fetching the primary repo.
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+
+ # Assert a warning or an error depending on what we're checking
+ if fail == "error":
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.PLUGIN, "git:unlisted-submodule")
+ else:
+ result.assert_success()
+ assert "git:unlisted-submodule" in result.stderr
+
+ # Verify that `bst show` will still not error out after fetching.
+ result = cli.run(project=project, args=["show", "target.bst"])
+ result.assert_success()
+ assert "git:unlisted-submodule" not in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("fail", ["warn", "error"])
+def test_track_unlisted_submodule(cli, tmpdir, datafiles, fail):
+ project = str(datafiles)
+
+ # Make the warning an error if we're testing errors
+ if fail == "error":
+ generate_project(project, config={"fatal-warnings": ["git:unlisted-submodule"]})
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ ref = repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created, but use
+ # the original ref, let the submodules appear after tracking
+ repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Create the source, and delete the explicit configuration
+ # of the submodules.
+ gitsource = repo.source_config(ref=ref)
+ del gitsource["submodules"]
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch the repo, we will not see the warning because we
+ # are still pointing to a ref which predates the submodules
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ assert "git:unlisted-submodule" not in result.stderr
+
+ # We won't get a warning/error when tracking either, the source
+ # has not become cached so the opportunity to check
+ # for the warning has not yet arisen.
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+ assert "git:unlisted-submodule" not in result.stderr
+
+ # Fetching the repo at the new ref will finally reveal the warning
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ if fail == "error":
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.PLUGIN, "git:unlisted-submodule")
+ else:
+ result.assert_success()
+ assert "git:unlisted-submodule" in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("fail", ["warn", "error"])
+def test_invalid_submodule(cli, tmpdir, datafiles, fail):
+ project = str(datafiles)
+
+ # Make the warning an error if we're testing errors
+ if fail == "error":
+ generate_project(project, config={"fatal-warnings": ["git:invalid-submodule"]})
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ ref = repo.create(os.path.join(project, "repofiles"))
+
+ # Create the source without any submodules, and add
+ # an invalid submodule configuration to it.
+ #
+ # We expect this to cause an invalid submodule warning
+ # after the source has been fetched and we know what
+ # the real submodules actually are.
+ #
+ gitsource = repo.source_config(ref=ref)
+ gitsource["submodules"] = {"subdir": {"url": "https://pony.org/repo.git"}}
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ # The warning or error is reported during fetch. There should be no
+ # error with `bst show`.
+ result = cli.run(project=project, args=["show", "target.bst"])
+ result.assert_success()
+ assert "git:invalid-submodule" not in result.stderr
+
+ # We will notice this directly in fetch, as it will try to fetch
+ # the submodules it discovers as a result of fetching the primary repo.
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+
+ # Assert a warning or an error depending on what we're checking
+ if fail == "error":
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.PLUGIN, "git:invalid-submodule")
+ else:
+ result.assert_success()
+ assert "git:invalid-submodule" in result.stderr
+
+ # Verify that `bst show` will still not error out after fetching.
+ result = cli.run(project=project, args=["show", "target.bst"])
+ result.assert_success()
+ assert "git:invalid-submodule" not in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.skipif(HAVE_OLD_GIT, reason="old git rm does not update .gitmodules")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("fail", ["warn", "error"])
+def test_track_invalid_submodule(cli, tmpdir, datafiles, fail):
+ project = str(datafiles)
+
+ # Make the warning an error if we're testing errors
+ if fail == "error":
+ generate_project(project, config={"fatal-warnings": ["git:invalid-submodule"]})
+
+ # Create the submodule first from the 'subrepofiles' subdir
+ subrepo = create_repo("git", str(tmpdir), "subrepo")
+ subrepo.create(os.path.join(project, "subrepofiles"))
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+
+ # Add a submodule pointing to the one we created
+ ref = repo.add_submodule("subdir", "file://" + subrepo.repo)
+
+ # Add a commit beyond the ref which *removes* the submodule we've added
+ repo.remove_path("subdir")
+
+ # Create the source, this will keep the submodules so initially
+ # the configuration is valid for the ref we're using
+ gitsource = repo.source_config(ref=ref)
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [gitsource]}
+ generate_element(project, "target.bst", element)
+
+ # Fetch the repo, we will not see the warning because we
+ # are still pointing to a ref which predates the submodules
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+ assert "git:invalid-submodule" not in result.stderr
+
+ # After tracking we're pointing to a ref, which would trigger an invalid
+ # submodule warning. However, cache validation is only performed as part
+ # of fetch.
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+
+ # Fetch to trigger cache validation
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ if fail == "error":
+ result.assert_main_error(ErrorDomain.STREAM, None)
+ result.assert_task_error(ErrorDomain.PLUGIN, "git:invalid-submodule")
+ else:
+ result.assert_success()
+ assert "git:invalid-submodule" in result.stderr
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("ref_format", ["sha1", "git-describe"])
+@pytest.mark.parametrize("tag,extra_commit", [(False, False), (True, False), (True, True)])
+def test_track_fetch(cli, tmpdir, datafiles, ref_format, tag, extra_commit):
+ project = str(datafiles)
+
+ # Create the repo from 'repofiles' subdir
+ repo = create_repo("git", str(tmpdir))
+ repo.create(os.path.join(project, "repofiles"))
+ if tag:
+ repo.add_tag("tag")
+ if extra_commit:
+ repo.add_commit()
+
+ # Write out our test target
+ element = {"kind": "import", "sources": [repo.source_config()]}
+ element["sources"][0]["ref-format"] = ref_format
+ generate_element(project, "target.bst", element)
+ element_path = os.path.join(project, "target.bst")
+
+ # Track it
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+
+ element = load_yaml(element_path)
+ new_ref = element.get_sequence("sources").mapping_at(0).get_str("ref")
+
+ if ref_format == "git-describe" and tag:
+ # Check and strip prefix
+ prefix = "tag-{}-g".format(0 if not extra_commit else 1)
+ assert new_ref.startswith(prefix)
+ new_ref = new_ref[len(prefix) :]
+
+ # 40 chars for SHA-1
+ assert len(new_ref) == 40
+
+ # Fetch it
+ result = cli.run(project=project, args=["source", "fetch", "target.bst"])
+ result.assert_success()
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.skipif(HAVE_OLD_GIT, reason="old git describe lacks --first-parent")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("ref_storage", [("inline"), ("project.refs")])
+@pytest.mark.parametrize("tag_type", [("annotated"), ("lightweight")])
+def test_git_describe(cli, tmpdir, datafiles, ref_storage, tag_type):
+ project = str(datafiles)
+
+ project_config = load_yaml(os.path.join(project, "project.conf"))
+ project_config["ref-storage"] = ref_storage
+ generate_project(project, config=project_config)
+
+ repofiles = os.path.join(str(tmpdir), "repofiles")
+ os.makedirs(repofiles, exist_ok=True)
+ file0 = os.path.join(repofiles, "file0")
+ with open(file0, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ repo = create_repo("git", str(tmpdir))
+
+ def tag(name):
+ if tag_type == "annotated":
+ repo.add_annotated_tag(name, name)
+ else:
+ repo.add_tag(name)
+
+ repo.create(repofiles)
+ tag("uselesstag")
+
+ file1 = os.path.join(str(tmpdir), "file1")
+ with open(file1, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file1)
+ tag("tag1")
+
+ file2 = os.path.join(str(tmpdir), "file2")
+ with open(file2, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.branch("branch2")
+ repo.add_file(file2)
+ tag("tag2")
+
+ repo.checkout("master")
+ file3 = os.path.join(str(tmpdir), "file3")
+ with open(file3, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file3)
+
+ repo.merge("branch2")
+
+ config = repo.source_config()
+ config["track"] = repo.latest_commit()
+ config["track-tags"] = True
+
+ # Write out our test target
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+ element_path = os.path.join(project, "target.bst")
+
+ if ref_storage == "inline":
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+ else:
+ result = cli.run(project=project, args=["source", "track", "target.bst", "--deps", "all"])
+ result.assert_success()
+
+ if ref_storage == "inline":
+ element = load_yaml(element_path)
+ tags = element.get_sequence("sources").mapping_at(0).get_sequence("tags")
+ assert len(tags) == 2
+ for tag in tags:
+ assert "tag" in tag
+ assert "commit" in tag
+ assert "annotated" in tag
+ assert tag.get_bool("annotated") == (tag_type == "annotated")
+
+ assert {(tag.get_str("tag"), tag.get_str("commit")) for tag in tags} == {
+ ("tag1", repo.rev_parse("tag1^{commit}")),
+ ("tag2", repo.rev_parse("tag2^{commit}")),
+ }
+
+ checkout = os.path.join(str(tmpdir), "checkout")
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkout])
+ result.assert_success()
+
+ if tag_type == "annotated":
+ options = []
+ else:
+ options = ["--tags"]
+ describe = subprocess.check_output(["git", "describe", *options], cwd=checkout, universal_newlines=True)
+ assert describe.startswith("tag2-2-")
+
+ describe_fp = subprocess.check_output(
+ ["git", "describe", "--first-parent", *options], cwd=checkout, universal_newlines=True
+ )
+ assert describe_fp.startswith("tag1-2-")
+
+ tags = subprocess.check_output(["git", "tag"], cwd=checkout, universal_newlines=True)
+ tags = set(tags.splitlines())
+ assert tags == set(["tag1", "tag2"])
+
+ with pytest.raises(subprocess.CalledProcessError):
+ subprocess.run(["git", "log", repo.rev_parse("uselesstag")], cwd=checkout, check=True)
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+@pytest.mark.parametrize("ref_storage", [("inline"), ("project.refs")])
+@pytest.mark.parametrize("tag_type", [("annotated"), ("lightweight")])
+def test_git_describe_head_is_tagged(cli, tmpdir, datafiles, ref_storage, tag_type):
+ project = str(datafiles)
+
+ project_config = load_yaml(os.path.join(project, "project.conf"))
+ project_config["ref-storage"] = ref_storage
+ generate_project(project, config=project_config)
+
+ repofiles = os.path.join(str(tmpdir), "repofiles")
+ os.makedirs(repofiles, exist_ok=True)
+ file0 = os.path.join(repofiles, "file0")
+ with open(file0, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ repo = create_repo("git", str(tmpdir))
+
+ def tag(name):
+ if tag_type == "annotated":
+ repo.add_annotated_tag(name, name)
+ else:
+ repo.add_tag(name)
+
+ repo.create(repofiles)
+ tag("uselesstag")
+
+ file1 = os.path.join(str(tmpdir), "file1")
+ with open(file1, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file1)
+
+ file2 = os.path.join(str(tmpdir), "file2")
+ with open(file2, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.branch("branch2")
+ repo.add_file(file2)
+
+ repo.checkout("master")
+ file3 = os.path.join(str(tmpdir), "file3")
+ with open(file3, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file3)
+
+ tagged_ref = repo.merge("branch2")
+ tag("tag")
+
+ config = repo.source_config()
+ config["track"] = repo.latest_commit()
+ config["track-tags"] = True
+
+ # Write out our test target
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+ element_path = os.path.join(project, "target.bst")
+
+ if ref_storage == "inline":
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+ else:
+ result = cli.run(project=project, args=["source", "track", "target.bst", "--deps", "all"])
+ result.assert_success()
+
+ if ref_storage == "inline":
+ element = load_yaml(element_path)
+ source = element.get_sequence("sources").mapping_at(0)
+ tags = source.get_sequence("tags")
+ assert len(tags) == 1
+
+ tag = source.get_sequence("tags").mapping_at(0)
+ assert "tag" in tag
+ assert "commit" in tag
+ assert "annotated" in tag
+ assert tag.get_bool("annotated") == (tag_type == "annotated")
+
+ tag_name = tag.get_str("tag")
+ commit = tag.get_str("commit")
+ assert (tag_name, commit) == ("tag", repo.rev_parse("tag^{commit}"))
+
+ checkout = os.path.join(str(tmpdir), "checkout")
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkout])
+ result.assert_success()
+
+ if tag_type == "annotated":
+ options = []
+ else:
+ options = ["--tags"]
+ describe = subprocess.check_output(["git", "describe", *options], cwd=checkout, universal_newlines=True)
+ assert describe.startswith("tag")
+
+ tags = subprocess.check_output(["git", "tag"], cwd=checkout, universal_newlines=True)
+ tags = set(tags.splitlines())
+ assert tags == set(["tag"])
+
+ rev_list = subprocess.check_output(["git", "rev-list", "--all"], cwd=checkout, universal_newlines=True)
+
+ assert set(rev_list.splitlines()) == set([tagged_ref])
+
+ with pytest.raises(subprocess.CalledProcessError):
+ subprocess.run(["git", "log", repo.rev_parse("uselesstag")], cwd=checkout, check=True)
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_git_describe_relevant_history(cli, tmpdir, datafiles):
+ project = str(datafiles)
+
+ project_config = load_yaml(os.path.join(project, "project.conf"))
+ project_config["ref-storage"] = "project.refs"
+ generate_project(project, config=project_config)
+
+ repofiles = os.path.join(str(tmpdir), "repofiles")
+ os.makedirs(repofiles, exist_ok=True)
+ file0 = os.path.join(repofiles, "file0")
+ with open(file0, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ repo = create_repo("git", str(tmpdir))
+ repo.create(repofiles)
+
+ file1 = os.path.join(str(tmpdir), "file1")
+ with open(file1, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file1)
+ repo.branch("branch")
+ repo.checkout("master")
+
+ file2 = os.path.join(str(tmpdir), "file2")
+ with open(file2, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ repo.add_file(file2)
+
+ file3 = os.path.join(str(tmpdir), "file3")
+ with open(file3, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ branch_boundary = repo.add_file(file3)
+
+ repo.checkout("branch")
+ file4 = os.path.join(str(tmpdir), "file4")
+ with open(file4, "w", encoding="utf-8") as f:
+ f.write("test\n")
+ tagged_ref = repo.add_file(file4)
+ repo.add_annotated_tag("tag1", "tag1")
+
+ head = repo.merge("master")
+
+ config = repo.source_config()
+ config["track"] = head
+ config["track-tags"] = True
+
+ # Write out our test target
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+
+ result = cli.run(project=project, args=["source", "track", "target.bst", "--deps", "all"])
+ result.assert_success()
+
+ checkout = os.path.join(str(tmpdir), "checkout")
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+ result = cli.run(project=project, args=["artifact", "checkout", "target.bst", "--directory", checkout])
+ result.assert_success()
+
+ describe = subprocess.check_output(["git", "describe"], cwd=checkout, universal_newlines=True)
+ assert describe.startswith("tag1-2-")
+
+ rev_list = subprocess.check_output(["git", "rev-list", "--all"], cwd=checkout, universal_newlines=True)
+
+ assert set(rev_list.splitlines()) == set([head, tagged_ref, branch_boundary])
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_default_do_not_track_tags(cli, tmpdir, datafiles):
+ project = str(datafiles)
+
+ project_config = load_yaml(os.path.join(project, "project.conf"))
+ project_config["ref-storage"] = "inline"
+ generate_project(project, config=project_config)
+
+ repofiles = os.path.join(str(tmpdir), "repofiles")
+ os.makedirs(repofiles, exist_ok=True)
+ file0 = os.path.join(repofiles, "file0")
+ with open(file0, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ repo = create_repo("git", str(tmpdir))
+
+ repo.create(repofiles)
+ repo.add_tag("tag")
+
+ config = repo.source_config()
+ config["track"] = repo.latest_commit()
+
+ # Write out our test target
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+ element_path = os.path.join(project, "target.bst")
+
+ result = cli.run(project=project, args=["source", "track", "target.bst"])
+ result.assert_success()
+
+ element = load_yaml(element_path)
+ source = element.get_sequence("sources").mapping_at(0)
+ assert "tags" not in source
+
+
+@pytest.mark.skipif(HAVE_GIT is False, reason="git is not available")
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "template"))
+def test_overwrite_rogue_tag_multiple_remotes(cli, tmpdir, datafiles):
+ """When using multiple remotes in cache (i.e. when using aliases), we
+ need to make sure we override tags. This is not allowed to fetch
+ tags that were present from different origins
+ """
+
+ project = str(datafiles)
+
+ repofiles = os.path.join(str(tmpdir), "repofiles")
+ os.makedirs(repofiles, exist_ok=True)
+ file0 = os.path.join(repofiles, "file0")
+ with open(file0, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ repo = create_repo("git", str(tmpdir))
+
+ top_commit = repo.create(repofiles)
+
+ repodir, reponame = os.path.split(repo.repo)
+ project_config = load_yaml(os.path.join(project, "project.conf"))
+ project_config["aliases"] = Node.from_dict({"repo": "http://example.com/"})
+ project_config["mirrors"] = [{"name": "middle-earth", "aliases": {"repo": ["file://{}/".format(repodir)]}}]
+ generate_project(project, config=project_config)
+
+ repo.add_annotated_tag("tag", "tag")
+
+ file1 = os.path.join(repofiles, "file1")
+ with open(file1, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ ref = repo.add_file(file1)
+
+ config = repo.source_config(ref=ref)
+ del config["track"]
+ config["url"] = "repo:{}".format(reponame)
+
+ # Write out our test target
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
+
+ repo.checkout(top_commit)
+
+ file2 = os.path.join(repofiles, "file2")
+ with open(file2, "w", encoding="utf-8") as f:
+ f.write("test\n")
+
+ new_ref = repo.add_file(file2)
+
+ repo.delete_tag("tag")
+ repo.add_annotated_tag("tag", "tag")
+ repo.checkout("master")
+
+ otherpath = os.path.join(str(tmpdir), "other_path")
+ shutil.copytree(repo.repo, os.path.join(otherpath, "repo"))
+ create_repo("git", otherpath)
+
+ repodir, reponame = os.path.split(repo.repo)
+
+ generate_project(project, config=project_config)
+
+ config = repo.source_config(ref=new_ref)
+ del config["track"]
+ config["url"] = "repo:{}".format(reponame)
+
+ element = {
+ "kind": "import",
+ "sources": [config],
+ }
+ generate_element(project, "target.bst", element)
+
+ result = cli.run(project=project, args=["build", "target.bst"])
+ result.assert_success()
diff --git a/tests/sources/git/project-override/project.conf b/tests/sources/git/project-override/project.conf
new file mode 100644
index 0000000..01c9016
--- /dev/null
+++ b/tests/sources/git/project-override/project.conf
@@ -0,0 +1,12 @@
+# Basic project
+name: foo
+min-version: 2.0
+sources:
+ git:
+ config:
+ checkout-submodules: False
+elements:
+ manual:
+ config:
+ build-commands:
+ - "foo"
diff --git a/tests/sources/git/project-override/repofiles/file.txt b/tests/sources/git/project-override/repofiles/file.txt
new file mode 100644
index 0000000..f621448
--- /dev/null
+++ b/tests/sources/git/project-override/repofiles/file.txt
@@ -0,0 +1 @@
+pony
diff --git a/tests/sources/git/project-override/subrepofiles/ponyfile.txt b/tests/sources/git/project-override/subrepofiles/ponyfile.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/tests/sources/git/project-override/subrepofiles/ponyfile.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/sources/git/template/inconsistent-submodule/.gitmodules b/tests/sources/git/template/inconsistent-submodule/.gitmodules
new file mode 100644
index 0000000..67271b8
--- /dev/null
+++ b/tests/sources/git/template/inconsistent-submodule/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "farm/pony"]
+ path = farm/pony
+ url = git://pony.com
diff --git a/tests/sources/git/template/othersubrepofiles/unicornfile.txt b/tests/sources/git/template/othersubrepofiles/unicornfile.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/tests/sources/git/template/othersubrepofiles/unicornfile.txt
@@ -0,0 +1 @@
+file
diff --git a/tests/sources/git/template/project.conf b/tests/sources/git/template/project.conf
new file mode 100644
index 0000000..dc34380
--- /dev/null
+++ b/tests/sources/git/template/project.conf
@@ -0,0 +1,3 @@
+# Basic project
+name: foo
+min-version: 2.0
diff --git a/tests/sources/git/template/repofiles/file.txt b/tests/sources/git/template/repofiles/file.txt
new file mode 100644
index 0000000..f621448
--- /dev/null
+++ b/tests/sources/git/template/repofiles/file.txt
@@ -0,0 +1 @@
+pony
diff --git a/tests/sources/git/template/subrepofiles/ponyfile.txt b/tests/sources/git/template/subrepofiles/ponyfile.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/tests/sources/git/template/subrepofiles/ponyfile.txt
@@ -0,0 +1 @@
+file