Reputation: 55826
In the company I work for, some projects have an project.info
file which contains the current version of the program/library/whatever.
Actually, when someone wants to tag a version, he must first ensure that the project.info
file (which is versionned) is up-to-date and contains the same version than the name of the tag he is about to create. No need to say that this is error prone.
We work on a clients-server workflow for git (all commits go to the same central repository) so I wonder: is there a way (a hook perhaps ?) to make this central repository refuse tags for which the project.info
does not match ?
What should I look for to get started ?
Thank you very much.
Upvotes: 2
Views: 4533
Reputation: 55826
Thanks to all the advices here, I succeeded.
Here is my final update
hook script:
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
allowwildtag=$(git config --bool hooks.allowwildtag)
allowunmatchedtag=$(git config --bool hooks.allowunmatchedtag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowwildtag" != "true" ] && ./hooks/check_tag -r $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' does not match the naming constraints." >&2
echo "*** Tags must follow the 'x.y-z' pattern, where x, y, and z are numeric characters." >&2
exit 1
fi
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
if [ "$allowunmatchedtag" != "true" ]
then
project_version=`./hooks/extract_project_version $newrev 2>/dev/null`
if [ "$project_version" == "" ]
then
# We dont output anything in case of success
#echo "*** Project does not contain a project.info file. No tag match performed."
:
elif [ "$project_version" == "error" ]
then
# The project contains an invalid project.info: we accept the tag but warn about it.
echo "*** Project contains an invalid project.info file. No tag match performed."
else
tag_version=${refname##refs/tags/}
if [ "$project_version" != "$tag_version" ]
then
echo "*** Tag and project version do not match: $tag_version != $project_version"
echo "*** Please check your project.info file."
exit 1
fi
fi
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0
And here is my extract_project_version
script:
#!/bin/bash
rev=$1
if [ "$rev" == "" ]
then
echo "Missing revision parameter." >&2
exit 1
fi
tmpdir=/tmp/$$.extract_project_version
mkdir -p $tmpdir
git archive $rev | tar -x -C $tmpdir
if [ -e "$tmpdir/project.info" ]
then
echo $tmpdir/project.info
fi
rm -rf $tmpdir
And now it works perfectly :)
Upvotes: 3
Reputation: 8976
Server-side
If you plan on using hooks, a post-receive hook (server refs updated) could create a commit with a change on project.info
if it has been forgotten, but the initial tagging commit would not have the right information in the file...
If you want to validate this before updating the refs, the problem is that pre-receive/update hooks do not actually have the information required to check the validity of project.info
(they get the name of the ref being updated, the old object name stored in the ref and the new objectname to be stored in the ref).
You can find some examples of hooks here and some information there.
Some other Stack Overflow topics on this subject :
Client-side
This would not ensure anything since clients could decide not to apply the proper method. Still, a post-commit hook could probably do the trick.
Upvotes: 0