Commit 0caa4655ebdb7bf028df970d0651378d121fab3e

Sven Strickroth 2020-09-09T10:48:00

Add git_tag_name_is_valid Signed-off-by: Sven Strickroth <email@cs-ware.de>

diff --git a/include/git2/tag.h b/include/git2/tag.h
index 4e5fe1d..a392136 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -365,6 +365,18 @@ GIT_EXTERN(int) git_tag_peel(
  */
 GIT_EXTERN(int) git_tag_dup(git_tag **out, git_tag *source);
 
+/**
+ * Determine whether a tag name is valid, meaning that (when prefixed
+ * with `refs/tags/`) that it is a valid reference name, and that any
+ * additional tag name restrictions are imposed (eg, it cannot start
+ * with a `-`).
+ *
+ * @param valid output pointer to set with validity of given tag name
+ * @param name a tag name to test
+ * @return 0 on success or an error code
+ */
+GIT_EXTERN(int) git_tag_name_is_valid(int *valid, const char *name);
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/src/tag.c b/src/tag.c
index 037dc66..8a4d6ee 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -522,6 +522,31 @@ int git_tag_peel(git_object **tag_target, const git_tag *tag)
 	return git_object_peel(tag_target, (const git_object *)tag, GIT_OBJECT_ANY);
 }
 
+int git_tag_name_is_valid(int *valid, const char *name)
+{
+	git_buf ref_name = GIT_BUF_INIT;
+	int error = 0;
+
+	GIT_ASSERT(valid);
+
+	/*
+	 * Discourage tag name starting with dash,
+	 * https://github.com/git/git/commit/4f0accd638b8d2
+	 */
+	if (!name || name[0] == '-')
+		goto done;
+
+	if ((error = git_buf_puts(&ref_name, GIT_REFS_TAGS_DIR)) < 0 ||
+	    (error = git_buf_puts(&ref_name, name)) < 0)
+		goto done;
+
+	error = git_reference_name_is_valid(valid, ref_name.ptr);
+
+done:
+	git_buf_dispose(&ref_name);
+	return error;
+}
+
 /* Deprecated Functions */
 
 #ifndef GIT_DEPRECATE_HARD
diff --git a/tests/refs/tags/name.c b/tests/refs/tags/name.c
new file mode 100644
index 0000000..0ca5df7
--- /dev/null
+++ b/tests/refs/tags/name.c
@@ -0,0 +1,17 @@
+#include "clar_libgit2.h"
+
+static int name_is_valid(const char *name)
+{
+	int valid;
+	cl_git_pass(git_tag_name_is_valid(&valid, name));
+	return valid;
+}
+
+void test_refs_tags_is_name_valid(void)
+{
+	cl_assert_equal_i(true, name_is_valid("sometag"));
+	cl_assert_equal_i(true, name_is_valid("test/sometag"));
+
+	cl_assert_equal_i(false, name_is_valid(""));
+	cl_assert_equal_i(false, name_is_valid("-dash"));
+}