diff --git a/include/git2/tag.h b/include/git2/tag.h index f82a6c9f9..a9773be56 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -144,6 +144,10 @@ GIT_EXTERN(const char *) git_tag_message(const git_tag *tag); * The message will not be cleaned up. This can be achieved * through `git_message_prettify()`. * + * The tag name will be checked for validity. You must avoid + * the characters '~', '^', ':', '\\', '?', '[', and '*', and the + * sequences ".." and "@{" which have special meaning to revparse. + * * @param oid Pointer where to store the OID of the * newly created tag. If the tag already exists, this parameter * will be the oid of the existing tag, and the function will @@ -165,7 +169,7 @@ GIT_EXTERN(const char *) git_tag_message(const git_tag *tag); * * @param force Overwrite existing references * - * @return 0 or an error code + * @return 0 on success, GIT_EINVALIDSPEC or an error code * A tag object is written to the ODB, and a proper reference * is written in the /refs/tags folder, pointing to it */ @@ -200,6 +204,9 @@ GIT_EXTERN(int) git_tag_create_frombuffer( * this target object. If `force` is true and a reference * already exists with the given name, it'll be replaced. * + * The tag name will be checked for validity. + * See `git_tag_create()` for rules about valid names. + * * @param oid Pointer where to store the OID of the provided * target object. If the tag already exists, this parameter * will be filled with the oid of the existing pointed object @@ -216,7 +223,7 @@ GIT_EXTERN(int) git_tag_create_frombuffer( * * @param force Overwrite existing references * - * @return 0 or an error code + * @return 0 on success, GIT_EINVALIDSPEC or an error code * A proper reference is written in the /refs/tags folder, * pointing to the provided target object */ @@ -230,12 +237,15 @@ GIT_EXTERN(int) git_tag_create_lightweight( /** * Delete an existing tag reference. * + * The tag name will be checked for validity. + * See `git_tag_create()` for rules about valid names. + * * @param repo Repository where lives the tag * * @param tag_name Name of the tag to be deleted; * this name is validated for consistency. * - * @return 0 or an error code + * @return 0 on success, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_tag_delete( git_repository *repo, diff --git a/src/tag.c b/src/tag.c index 606afd657..94915ad78 100644 --- a/src/tag.c +++ b/src/tag.c @@ -251,7 +251,7 @@ static int git_tag_create__internal( error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); if (error < 0 && error != GIT_ENOTFOUND) - return -1; + goto cleanup; /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explictly been requested **/ @@ -269,6 +269,7 @@ static int git_tag_create__internal( error = git_reference_create(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite); +cleanup: git_reference_free(new_ref); git_buf_free(&ref_name); return error; @@ -384,7 +385,7 @@ int git_tag_delete(git_repository *repo, const char *tag_name) git_buf_free(&ref_name); if (error < 0) - return -1; + return error; return git_reference_delete(tag_ref); } diff --git a/tests-clar/object/tag/write.c b/tests-clar/object/tag/write.c index ad6ca76b2..eb0ac2897 100644 --- a/tests-clar/object/tag/write.c +++ b/tests-clar/object/tag/write.c @@ -88,7 +88,6 @@ void test_object_tag_write__overwrite(void) git_object_free(target); git_signature_free(tagger); - } void test_object_tag_write__replace(void) @@ -190,3 +189,33 @@ void test_object_tag_write__delete(void) git_reference_free(ref_tag); } + +void test_object_tag_write__creating_with_an_invalid_name_returns_EINVALIDSPEC(void) +{ + git_oid target_id, tag_id; + git_signature *tagger; + git_object *target; + + git_oid_fromstr(&target_id, tagged_commit); + cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJ_COMMIT)); + + cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); + + cl_assert_equal_i(GIT_EINVALIDSPEC, + git_tag_create(&tag_id, g_repo, + "Inv@{id", target, tagger, tagger_message, 0) + ); + + cl_assert_equal_i(GIT_EINVALIDSPEC, + git_tag_create_lightweight(&tag_id, g_repo, + "Inv@{id", target, 0) + ); + + git_object_free(target); + git_signature_free(tagger); +} + +void test_object_tag_write__deleting_with_an_invalid_name_returns_EINVALIDSPEC(void) +{ + cl_assert_equal_i(GIT_EINVALIDSPEC, git_tag_delete(g_repo, "Inv@{id")); +}