Commit 3f8987a2971ec32690b2b854c9a64935f2f31f09

Create projects using gitorious hooks

Commit diff

app/models/repository.rb

 
2929 end
3030
3131 def self.create_git_repository(path)
32 git_backend.create(full_path_from_partial_path(path))
32 full_path = full_path_from_partial_path(path)
33 git_backend.create(full_path)
34
35 hooks = File.join(GitoriousConfig["repository_base_path"], ".hooks")
36 Dir.chdir(full_path) do
37 hooks_base_path = File.expand_path(File.join(File.dirname(__FILE__), "../../data/hooks")) # FIXME: the hooks are in GITORIOUS_ROOT/data/hooks
38
39 if not File.symlink?(hooks)
40 if not File.exist?(hooks)
41 FileUtils.ln_s(hooks_base_path, hooks) # Create symlink
42 end
43 elsif File.expand_path(File.readlink(hooks)) != hooks_base_path
44 FileUtils.ln_sf(hooks_base_path, hooks) # Fixup symlink
45 end
46 end
47
48 local_hooks = File.join(full_path, "hooks")
49 unless File.exist?(local_hooks)
50 target_path = Pathname.new(hooks).relative_path_from(Pathname.new(full_path))
51 Dir.chdir(full_path) do
52 FileUtils.ln_s(target_path, "hooks")
53 end
54 end
55
56 File.open(File.join(full_path, "description"), "w") do |file|
57 file << path.sub(/\.git$/, "") << "\n"
58 end
3359 end
3460
3561 def self.clone_git_repository(target_path, source_path)
toggle raw diff

data/git-template/hooks/applypatch-msg

 
0#!/bin/sh
1#
2# An example hook script to check the commit log message taken by
3# applypatch from an e-mail message.
4#
5# The hook should exit with non-zero status after issuing an
6# appropriate message if it wants to stop the commit. The hook is
7# allowed to edit the commit message file.
8#
9# To enable this hook, make this file executable.
10
11. git-sh-setup
12test -x "$GIT_DIR/hooks/commit-msg" &&
13 exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
14:
toggle raw diff

data/git-template/hooks/commit-msg

 
0#!/bin/sh
1#
2# An example hook script to check the commit log message.
3# Called by git-commit with one argument, the name of the file
4# that has the commit message. The hook should exit with non-zero
5# status after issuing an appropriate message if it wants to stop the
6# commit. The hook is allowed to edit the commit message file.
7#
8# To enable this hook, make this file executable.
9
10# Uncomment the below to add a Signed-off-by line to the message.
11# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
12# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
13
14# This example catches duplicate Signed-off-by lines.
15
16test "" = "$(grep '^Signed-off-by: ' "$1" |
17 sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
18 echo >&2 Duplicate Signed-off-by lines.
19 exit 1
20}
21
toggle raw diff

data/git-template/hooks/git.rb

 
0module Grit
1 class << self; attr_accessor :debug end
2# self.debug = true
3 class Git
4 undef_method :clone
5
6 class << self
7 attr_accessor :git_binary
8 end
9
10 self.git_binary = "/usr/bin/env git"
11
12 attr_accessor :git_dir
13
14 def initialize(git_dir)
15 self.git_dir = git_dir
16 end
17
18 def execute(command)
19 `#{command}`
20 end
21
22 # Run the given git command with the specified arguments and return
23 # the result as a String
24 # +cmd+ is the command
25 # +options+ is a hash of Ruby style options
26 # +args+ is the list of arguments (to be joined by spaces)
27 #
28 # Examples
29 # git.rev_list({:max_count => 10, :header => true}, "master")
30 #
31 # Returns String
32 def method_missing(cmd, options = {}, *args)
33 opt_args = transform_options(options)
34 ext_args = args.map { |a| (a == '--' or a =~ /^\s*\|/) ? a : "'#{e(a)}'" }
35
36 call = "#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}"
37 puts call if Grit.debug
38 response = execute(call)
39 puts response if Grit.debug
40 response
41 end
42
43 def shell_escape(str)
44 str.to_s.gsub("'", "\\\\'")
45 end
46 alias_method :e, :shell_escape
47
48 # Transform Ruby style options into git command line options
49 # +options+ is a hash of Ruby style options
50 #
51 # Returns String[]
52 # e.g. ["--max-count=10", "--header"]
53 def transform_options(options)
54 args = []
55 options.keys.each do |opt|
56 if opt.to_s.size == 1
57 if options[opt] == true
58 args << "-#{opt}"
59 else
60 val = options.delete(opt)
61 args << "-#{opt.to_s} '#{e(val)}'"
62 end
63 else
64 if options[opt] == true
65 args << "--#{opt.to_s.gsub(/_/, '-')}"
66 else
67 val = options.delete(opt)
68 args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
69 end
70 end
71 end
72 args
73 end
74 end # Git
75
76end # Grit
toggle raw diff

data/git-template/hooks/post-commit

 
0#!/bin/sh
1#
2# An example hook script that is called after a successful
3# commit is made.
4#
5# To enable this hook, make this file executable.
6
7: Nothing
toggle raw diff

data/git-template/hooks/post-receive

 
0#!/usr/bin/env ruby
1
2$: << File.dirname(__FILE__)
3require 'git'
4require 'date'
5
6gitdir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
7slug = File.basename(gitdir)
8
9if slug == "mainline.git"
10 slug = File.basename(File.expand_path(File.join(gitdir, "..")))
11end
12
13git = Grit::Git.new(gitdir)
14
15while line = gets
16 oldrev, newrev, revname = line.split(" ")
17 current_rev = newrev
18 newtype = oldtype = current_rev_type = "commit"
19
20 action = :create
21 if oldrev =~ /^0+$/
22 action = :create
23 else
24 if newrev =~ /^0+$/
25 action = :delete
26 else
27 action = :update
28 end
29 end
30
31 if action != :create
32 newtype = git.cat_file({:t => true}, newrev)
33 oldtype = git.cat_file({:t => true}, oldrev)
34 end
35
36 if action == :delete
37 current_rev = oldrev
38 current_rev_type = oldtype
39 end
40
41 path, type, name = revname.split("/")
42
43 info = git.show({ :pretty => "format:author: %cn%nemail: %ce%ndate: %cd%nmessage: %s", :s => true}, current_rev )
44
45 hash = {}
46 info.each { |line|
47 if line =~ /(\w+):\s(.*)$/
48 key = $1.to_sym
49 value = $2
50
51 value = Date.parse(value) if key == :date
52
53 hash[key] = value
54 end
55 }
56
57 puts "#{hash[:author]}: #{action} #{current_rev_type} on #{slug} [#{hash[:date]}]"
58 puts " #{hash[:message]}"
59
60end
61
62puts "=> Thanks!"
63
toggle raw diff

data/git-template/hooks/post-update

 
0#!/bin/sh
1#
2# An example hook script to prepare a packed repository for use over
3# dumb transports.
4#
5# To enable this hook, make this file executable by "chmod +x post-update".
6
7exec git-update-server-info
toggle raw diff

data/git-template/hooks/pre-applypatch

 
0#!/bin/sh
1#
2# An example hook script to verify what is about to be committed
3# by applypatch from an e-mail message.
4#
5# The hook should exit with non-zero status after issuing an
6# appropriate message if it wants to stop the commit.
7#
8# To enable this hook, make this file executable.
9
10. git-sh-setup
11test -x "$GIT_DIR/hooks/pre-commit" &&
12 exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
13:
14
toggle raw diff

data/git-template/hooks/pre-commit

 
0#!/bin/sh
1#
2# An example hook script to verify what is about to be committed.
3# Called by git-commit with no arguments. The hook should
4# exit with non-zero status after issuing an appropriate message if
5# it wants to stop the commit.
6#
7# To enable this hook, make this file executable.
8
9# This is slightly modified from Andrew Morton's Perfect Patch.
10# Lines you introduce should not have trailing whitespace.
11# Also check for an indentation that has SP before a TAB.
12
13if git-rev-parse --verify HEAD 2>/dev/null
14then
15 git-diff-index -p -M --cached HEAD
16else
17 # NEEDSWORK: we should produce a diff with an empty tree here
18 # if we want to do the same verification for the initial import.
19 :
20fi |
21perl -e '
22 my $found_bad = 0;
23 my $filename;
24 my $reported_filename = "";
25 my $lineno;
26 sub bad_line {
27 my ($why, $line) = @_;
28 if (!$found_bad) {
29 print STDERR "*\n";
30 print STDERR "* You have some suspicious patch lines:\n";
31 print STDERR "*\n";
32 $found_bad = 1;
33 }
34 if ($reported_filename ne $filename) {
35 print STDERR "* In $filename\n";
36 $reported_filename = $filename;
37 }
38 print STDERR "* $why (line $lineno)\n";
39 print STDERR "$filename:$lineno:$line\n";
40 }
41 while (<>) {
42 if (m|^diff --git a/(.*) b/\1$|) {
43 $filename = $1;
44 next;
45 }
46 if (/^@@ -\S+ \+(\d+)/) {
47 $lineno = $1 - 1;
48 next;
49 }
50 if (/^ /) {
51 $lineno++;
52 next;
53 }
54 if (s/^\+//) {
55 $lineno++;
56 chomp;
57 if (/\s$/) {
58 bad_line("trailing whitespace", $_);
59 }
60 if (/^\s* /) {
61 bad_line("indent SP followed by a TAB", $_);
62 }
63 if (/^(?:[<>=]){7}/) {
64 bad_line("unresolved merge conflict", $_);
65 }
66 }
67 }
68 exit($found_bad);
69'
70
toggle raw diff

data/git-template/hooks/pre-rebase

 
0#!/bin/sh
1#
2# Copyright (c) 2006 Junio C Hamano
3#
4
5publish=next
6basebranch="$1"
7if test "$#" = 2
8then
9 topic="refs/heads/$2"
10else
11 topic=`git symbolic-ref HEAD`
12fi
13
14case "$basebranch,$topic" in
15master,refs/heads/??/*)
16 ;;
17*)
18 exit 0 ;# we do not interrupt others.
19 ;;
20esac
21
22# Now we are dealing with a topic branch being rebased
23# on top of master. Is it OK to rebase it?
24
25# Is topic fully merged to master?
26not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
27if test -z "$not_in_master"
28then
29 echo >&2 "$topic is fully merged to master; better remove it."
30 exit 1 ;# we could allow it, but there is no point.
31fi
32
33# Is topic ever merged to next? If so you should not be rebasing it.
34only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
35only_next_2=`git-rev-list ^master ${publish} | sort`
36if test "$only_next_1" = "$only_next_2"
37then
38 not_in_topic=`git-rev-list "^$topic" master`
39 if test -z "$not_in_topic"
40 then
41 echo >&2 "$topic is already up-to-date with master"
42 exit 1 ;# we could allow it, but there is no point.
43 else
44 exit 0
45 fi
46else
47 not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
48 perl -e '
49 my $topic = $ARGV[0];
50 my $msg = "* $topic has commits already merged to public branch:\n";
51 my (%not_in_next) = map {
52 /^([0-9a-f]+) /;
53 ($1 => 1);
54 } split(/\n/, $ARGV[1]);
55 for my $elem (map {
56 /^([0-9a-f]+) (.*)$/;
57 [$1 => $2];
58 } split(/\n/, $ARGV[2])) {
59 if (!exists $not_in_next{$elem->[0]}) {
60 if ($msg) {
61 print STDERR $msg;
62 undef $msg;
63 }
64 print STDERR " $elem->[1]\n";
65 }
66 }
67 ' "$topic" "$not_in_next" "$not_in_master"
68 exit 1
69fi
70
71exit 0
72
73################################################################
74
75This sample hook safeguards topic branches that have been
76published from being rewound.
77
78The workflow assumed here is:
79
80 * Once a topic branch forks from "master", "master" is never
81 merged into it again (either directly or indirectly).
82
83 * Once a topic branch is fully cooked and merged into "master",
84 it is deleted. If you need to build on top of it to correct
85 earlier mistakes, a new topic branch is created by forking at
86 the tip of the "master". This is not strictly necessary, but
87 it makes it easier to keep your history simple.
88
89 * Whenever you need to test or publish your changes to topic
90 branches, merge them into "next" branch.
91
92The script, being an example, hardcodes the publish branch name
93to be "next", but it is trivial to make it configurable via
94$GIT_DIR/config mechanism.
95
96With this workflow, you would want to know:
97
98(1) ... if a topic branch has ever been merged to "next". Young
99 topic branches can have stupid mistakes you would rather
100 clean up before publishing, and things that have not been
101 merged into other branches can be easily rebased without
102 affecting other people. But once it is published, you would
103 not want to rewind it.
104
105(2) ... if a topic branch has been fully merged to "master".
106 Then you can delete it. More importantly, you should not
107 build on top of it -- other people may already want to
108 change things related to the topic as patches against your
109 "master", so if you need further changes, it is better to
110 fork the topic (perhaps with the same name) afresh from the
111 tip of "master".
112
113Let's look at this example:
114
115 o---o---o---o---o---o---o---o---o---o "next"
116 / / / /
117 / a---a---b A / /
118 / / / /
119 / / c---c---c---c B /
120 / / / \ /
121 / / / b---b C \ /
122 / / / / \ /
123 ---o---o---o---o---o---o---o---o---o---o---o "master"
124
125
126A, B and C are topic branches.
127
128 * A has one fix since it was merged up to "next".
129
130 * B has finished. It has been fully merged up to "master" and "next",
131 and is ready to be deleted.
132
133 * C has not merged to "next" at all.
134
135We would want to allow C to be rebased, refuse A, and encourage
136B to be deleted.
137
138To compute (1):
139
140 git-rev-list ^master ^topic next
141 git-rev-list ^master next
142
143 if these match, topic has not merged in next at all.
144
145To compute (2):
146
147 git-rev-list master..topic
148
149 if this is empty, it is fully merged to "master".
toggle raw diff

data/git-template/hooks/update

 
0#!/bin/sh
1#
2# An example hook script to blocks unannotated tags from entering.
3# Called by git-receive-pack with arguments: refname sha1-old sha1-new
4#
5# To enable this hook, make this file executable by "chmod +x update".
6#
7# Config
8# ------
9# hooks.allowunannotated
10# This boolean sets whether unannotated tags will be allowed into the
11# repository. By default they won't be.
12#
13
14# --- Command line
15refname="$1"
16oldrev="$2"
17newrev="$3"
18
19# --- Safety check
20if [ -z "$GIT_DIR" ]; then
21 echo "Don't run this script from the command line." >&2
22 echo " (if you want, you could supply GIT_DIR then run" >&2
23 echo " $0 <ref> <oldrev> <newrev>)" >&2
24 exit 1
25fi
26
27if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
28 echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
29 exit 1
30fi
31
32# --- Config
33allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
34
35# check for no description
36projectdesc=$(sed -e '1p' "$GIT_DIR/description")
37if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
38 echo "*** Project description file hasn't been set" >&2
39 exit 1
40fi
41
42# --- Check types
43# if $newrev is 0000...0000, it's a commit to delete a branch
44if [ -z "${newrev##0*}" ]; then
45 newrev_type=commit
46else
47 newrev_type=$(git-cat-file -t $newrev)
48fi
49
50case "$refname","$newrev_type" in
51 refs/tags/*,commit)
52 # un-annotated tag
53 short_refname=${refname##refs/tags/}
54 if [ "$allowunannotated" != "true" ]; then
55 echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
56 echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
57 exit 1
58 fi
59 ;;
60 refs/tags/*,tag)
61 # annotated tag
62 ;;
63 refs/heads/*,commit)
64 # branch
65 ;;
66 refs/remotes/*,commit)
67 # tracking branch
68 ;;
69 *)
70 # Anything else (is there anything else?)
71 echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
72 exit 1
73 ;;
74esac
75
76# --- Finished
77exit 0
toggle raw diff

data/hooks/applypatch-msg

 
1#!/bin/sh
2#
3# An example hook script to check the commit log message taken by
4# applypatch from an e-mail message.
5#
6# The hook should exit with non-zero status after issuing an
7# appropriate message if it wants to stop the commit. The hook is
8# allowed to edit the commit message file.
9#
10# To enable this hook, make this file executable.
11
12. git-sh-setup
13test -x "$GIT_DIR/hooks/commit-msg" &&
14 exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
15:
toggle raw diff

data/hooks/commit-msg

 
1#!/bin/sh
2#
3# An example hook script to check the commit log message.
4# Called by git-commit with one argument, the name of the file
5# that has the commit message. The hook should exit with non-zero
6# status after issuing an appropriate message if it wants to stop the
7# commit. The hook is allowed to edit the commit message file.
8#
9# To enable this hook, make this file executable.
10
11# Uncomment the below to add a Signed-off-by line to the message.
12# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
13# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
14
15# This example catches duplicate Signed-off-by lines.
16
17test "" = "$(grep '^Signed-off-by: ' "$1" |
18 sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
19 echo >&2 Duplicate Signed-off-by lines.
20 exit 1
21}
22
toggle raw diff

data/hooks/git.rb

 
1module Grit
2 class << self; attr_accessor :debug end
3# self.debug = true
4 class Git
5 undef_method :clone
6
7 class << self
8 attr_accessor :git_binary
9 end
10
11 self.git_binary = "/usr/bin/env git"
12
13 attr_accessor :git_dir
14
15 def initialize(git_dir)
16 self.git_dir = git_dir
17 end
18
19 def execute(command)
20 `#{command}`
21 end
22
23 # Run the given git command with the specified arguments and return
24 # the result as a String
25 # +cmd+ is the command
26 # +options+ is a hash of Ruby style options
27 # +args+ is the list of arguments (to be joined by spaces)
28 #
29 # Examples
30 # git.rev_list({:max_count => 10, :header => true}, "master")
31 #
32 # Returns String
33 def method_missing(cmd, options = {}, *args)
34 opt_args = transform_options(options)
35 ext_args = args.map { |a| (a == '--' or a =~ /^\s*\|/) ? a : "'#{e(a)}'" }
36
37 call = "#{Git.git_binary} --git-dir='#{self.git_dir}' #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}"
38 puts call if Grit.debug
39 response = execute(call)
40 puts response if Grit.debug
41 response
42 end
43
44 def shell_escape(str)
45 str.to_s.gsub("'", "\\\\'")
46 end
47 alias_method :e, :shell_escape
48
49 # Transform Ruby style options into git command line options
50 # +options+ is a hash of Ruby style options
51 #
52 # Returns String[]