From d3a9ec3002ca6d1cd6f5d66394c5a15c6d72cc18 Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Mon, 5 Feb 2018 12:20:12 -0800 Subject: [PATCH] Return the commit id for the recipe being read This adds returning the commit id from read_commit, and a new function read_recipe_and_id() that returns the commit id and the recipe in a tuple. If the commit is passed in, it is used as is. If no commit is passed in it finds the most recent commit for the file on the selected branch and returns that. Missing recipes now raise a RecipeError with an informative message. eg. "No commits for missing-recipe.toml on the master branch." --- src/pylorax/api/recipes.py | 41 ++++++++++++++++++++++++++++++----- tests/pylorax/test_recipes.py | 4 ++++ tests/pylorax/test_server.py | 2 +- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/pylorax/api/recipes.py b/src/pylorax/api/recipes.py index 5bceefb2..de1e5f62 100644 --- a/src/pylorax/api/recipes.py +++ b/src/pylorax/api/recipes.py @@ -335,14 +335,20 @@ def read_commit(repo, branch, filename, commit=None): :type filename: str :param commit: Optional commit hash :type commit: str - :returns: Contents of the commit - :rtype: str + :returns: The commit id, and the contents of the commit + :rtype: tuple(str, str) :raises: Can raise errors from Ggit If no commit is passed the master:filename is returned, otherwise it will be commit:filename """ - return read_commit_spec(repo, "%s:%s" % (commit or branch, filename)) + if not commit: + # Find the most recent commit for filename on the selected branch + commits = list_commits(repo, branch, filename, 1) + if not commits: + raise RecipeError("No commits for %s on the %s branch." % (filename, branch)) + commit = commits[0].commit + return (commit, read_commit_spec(repo, "%s:%s" % (commit, filename))) def read_recipe_commit(repo, branch, recipe_name, commit=None): """Read a recipe commit from git and return a Recipe object @@ -362,9 +368,30 @@ def read_recipe_commit(repo, branch, recipe_name, commit=None): If no commit is passed the master:filename is returned, otherwise it will be commit:filename """ - recipe_toml = read_commit(repo, branch, recipe_filename(recipe_name), commit) + (_, recipe_toml) = read_commit(repo, branch, recipe_filename(recipe_name), commit) return recipe_from_toml(recipe_toml) +def read_recipe_and_id(repo, branch, recipe_name, commit=None): + """Read a recipe commit and its id from git + + :param repo: Open repository + :type repo: Git.Repository + :param branch: Branch name + :type branch: str + :param recipe_name: Recipe name to read + :type recipe_name: str + :param commit: Optional commit hash + :type commit: str + :returns: The commit id, and a Recipe object + :rtype: tuple(str, Recipe) + :raises: Can raise errors from Ggit + + If no commit is passed the master:filename is returned, otherwise it will be + commit:filename + """ + (commit_id, recipe_toml) = read_commit(repo, branch, recipe_filename(recipe_name), commit) + return (commit_id, recipe_from_toml(recipe_toml)) + def list_branch_files(repo, branch): """Return a sorted list of the files on the branch HEAD @@ -671,7 +698,7 @@ class CommitDetails(DataHolder): message = message, revision = revision) -def list_commits(repo, branch, filename): +def list_commits(repo, branch, filename, limit=0): """List the commit history of a file on a branch. :param repo: Open repository @@ -680,6 +707,8 @@ def list_commits(repo, branch, filename): :type branch: str :param filename: filename to revert :type filename: str + :param limit: Number of commits to return (0=all) + :type limit: int :returns: A list of commit details :rtype: list(CommitDetails) :raises: Can raise errors from Ggit @@ -716,6 +745,8 @@ def list_commits(repo, branch, filename): tag = find_commit_tag(repo, branch, filename, commit.get_id()) try: commits.append(get_commit_details(commit, get_revision_from_tag(tag))) + if limit and len(commits) > limit: + break except CommitTimeValError: # Skip any commits that have trouble converting the time # TODO - log details about this failure diff --git a/tests/pylorax/test_recipes.py b/tests/pylorax/test_recipes.py index dfc54a27..50b7a544 100644 --- a/tests/pylorax/test_recipes.py +++ b/tests/pylorax/test_recipes.py @@ -203,6 +203,10 @@ class GitRecipesTest(unittest.TestCase): self.assertNotEqual(recipe, None) self.assertEqual(recipe["name"], "http-server") + # Read the recipe and its commit id + (commit_id, recipe) = recipes.read_recipe_and_id(self.repo, "master", "http-server", commits[0].commit) + self.assertEqual(commit_id, commits[0].commit) + def test_07_tag_commit(self): """Test tagging the most recent commit of a recipe""" result = recipes.tag_file_commit(self.repo, "master", "not-a-file") diff --git a/tests/pylorax/test_server.py b/tests/pylorax/test_server.py index 2f121afd..83b38162 100644 --- a/tests/pylorax/test_server.py +++ b/tests/pylorax/test_server.py @@ -113,7 +113,7 @@ class ServerTestCase(unittest.TestCase): self.assertEqual(data, info_dict_2) info_dict_3 = {"changes":[], - "errors":[{"recipe":"missing-recipe", "msg":"ggit-error: the path 'missing-recipe.toml' does not exist in the given tree (-3)"}], + "errors":[{"recipe":"missing-recipe", "msg":"No commits for missing-recipe.toml on the master branch."}], "recipes":[] } resp = self.server.get("/api/v0/recipes/info/missing-recipe")