|
1
|
# Hooks |
|
2
|
|
|
3
|
Hooks are short scripts that Fossil runs at defined points of processing. |
|
4
|
Administrators can use hooks to help enforce policy or connect Fossil to |
|
5
|
a continuous integration (CI) system. |
|
6
|
|
|
7
|
## Interim Documentation. |
|
8
|
|
|
9
|
* This is a work-in-progress. The interface is in flux. |
|
10
|
For the time being, the documentation is a list of |
|
11
|
bullet points. We hope to transform this into a proper document |
|
12
|
later, after things settle down. |
|
13
|
|
|
14
|
* Contributions and suggestions to the hook system and/or the |
|
15
|
documentation are welcomed. |
|
16
|
|
|
17
|
## General Notes. |
|
18
|
|
|
19
|
* Each hooks has a "type", a "sequence", and a "command". The command |
|
20
|
is a shell command that runs at the appropriate time. The type |
|
21
|
is currently one of "after-receive", "before-commit", "commit-msg", |
|
22
|
or "disabled". The sequence is an arbitrary integer. |
|
23
|
|
|
24
|
* There can be multiple hooks of the same type. When that is the |
|
25
|
case, the hooks are run in order of ascending sequence. |
|
26
|
|
|
27
|
* Use the "fossil hook" command to create, edit, and delete hooks. |
|
28
|
|
|
29
|
* Use the "fossil hook test" command to test new hooks. |
|
30
|
|
|
31
|
## Hook Scripts |
|
32
|
|
|
33
|
* All scripts are expected to run relatively quickly. If a long-running |
|
34
|
process is started by a hook, it should be run in the background so |
|
35
|
that the original script can return. |
|
36
|
|
|
37
|
* The "%F" sequence inside the script is translated into the |
|
38
|
name of the fossil executable. |
|
39
|
|
|
40
|
* The "%R" sequence in the script is translated into the name of |
|
41
|
the repository. |
|
42
|
|
|
43
|
* The "%A" sequence becomes the name of an auxiliary input file, |
|
44
|
the meaning of which depends on the hook type. The auxiliary filename |
|
45
|
might be an empty string. Take care to use appropriate quoting! |
|
46
|
|
|
47
|
## Disabled Hooks |
|
48
|
|
|
49
|
* Hooks with type "disabled" never run. They are a place-holder for |
|
50
|
scripts that might be converted to some other hook-type later. |
|
51
|
For example, the command "fossil hook edit --type disabled ID" |
|
52
|
can be used to temporarily disable the hook named ID, and then |
|
53
|
"fossil hook edit --type after-receive ID" can be used to reenable |
|
54
|
it later. |
|
55
|
|
|
56
|
## After-Receive Hooks |
|
57
|
|
|
58
|
* The "after-receive" hook is run by [the backoffice](./backoffice.md) |
|
59
|
whenever new artifacts are received into the repository. The artifacts |
|
60
|
have already been committed and so there is nothing that the |
|
61
|
after-receive hook can do to block them. |
|
62
|
|
|
63
|
* The after-receive hooks are intended to be run on a server to start |
|
64
|
up a background testing or CI process. But they can also be run |
|
65
|
on the client side. The key point is that after-receive hooks are |
|
66
|
invoked by backoffice, so backoffice must be running in order to |
|
67
|
fire after-receive hooks. |
|
68
|
|
|
69
|
* The exit code from the after-receive script is ignored. |
|
70
|
|
|
71
|
* The standard input to the after-receive hook is a list of |
|
72
|
new artifacts, one per line. The first token on each line is the |
|
73
|
hash of the new artifact. After the hash is a human-readable text |
|
74
|
description of what the artifact represents. |
|
75
|
|
|
76
|
* Sometimes the same artifact can represent two or more things. |
|
77
|
For example, the same artifact might represent two or more files |
|
78
|
in the check-out (assuming the files hold identical content). In |
|
79
|
that case, the text description that is input to the after-receive |
|
80
|
hook only shows one of the possible uses for the artifact. |
|
81
|
|
|
82
|
* If two or more pushes occur against a repository at about the same |
|
83
|
time, then the set of artifacts added by both pushes might be |
|
84
|
combined into a single after-receive callback. |
|
85
|
|
|
86
|
* Fossil holds a write transaction on the repository while the |
|
87
|
after-receive hook is running. If the script needs to access the |
|
88
|
database, then the database will need to be in WAL mode so that |
|
89
|
readers can co-exist with the writer. Or the script might just |
|
90
|
launch a background process that waits until the hook script finishes |
|
91
|
and the transaction commits before it tries to access the repository |
|
92
|
database. |
|
93
|
|
|
94
|
* A push might not deliver all of the artifacts for a checkin. If |
|
95
|
Fossil knows that a /xfer HTTP request is incomplete, it will defer |
|
96
|
running the after-receive push for 60 seconds, or until a complete |
|
97
|
/xfer request is received. This helps to prevent after-receive hooks |
|
98
|
from running when incomplete checkins exist in the repository, but |
|
99
|
it does not provide hard guarantees, as there is no way to do that |
|
100
|
in a distributed system. |
|
101
|
|
|
102
|
* The list of artifacts delivered to standard input of the |
|
103
|
after-receive hook will not contain more than 24-hours worth |
|
104
|
of artifacts. If the backoffice has been shut down for a while |
|
105
|
such that after-receive hooks have not been running, and more |
|
106
|
than 24-hours of changes have accumulated since the last run |
|
107
|
of an after-receive hook, then only the most recent 24-hours |
|
108
|
is included in the input. |
|
109
|
|
|
110
|
## Before-Commit Hooks |
|
111
|
|
|
112
|
* Before-commit hooks run during the "fossil commit" command before |
|
113
|
the user is prompted for the check-in comment. Fossil holds |
|
114
|
a write-transaction on the repository when the before-commit |
|
115
|
hook is running, so the repository needs to be in WAL mode if the |
|
116
|
script needs to access the repository. |
|
117
|
|
|
118
|
* The %A substitution is the name of a "commit description file" that |
|
119
|
shows the details of the commit in progress. To see what a |
|
120
|
"commit description file" looks like, set a before-commit hook |
|
121
|
with a command of "cat %A" and then run a sample commit with |
|
122
|
the --dry-run option. |
|
123
|
|
|
124
|
* If any before-commit hook returns a non-zero exit code, then |
|
125
|
the commit is abandoned. All |
|
126
|
before-commit hooks must exit(0) in order for the commit to |
|
127
|
proceed. |
|
128
|
|
|
129
|
* The --no-validate flag to the "fossil commit" command prevents any |
|
130
|
before-commit hooks from running. |
|
131
|
|
|
132
|
* The --trace flag to the "fossil commit" command shows each |
|
133
|
before-commit hook as it is run. |
|
134
|
|
|
135
|
* If a before-commit hook fails, it should print an error message |
|
136
|
on standard output or standard error. Otherwise, the user won't |
|
137
|
know what went wrong, because Fossil won't tell them. |
|
138
|
|
|
139
|
* Nothing is written to standard input of the before-commit hook. |
|
140
|
The information transmitted to the before-commit hook is contained |
|
141
|
in the "%A" auxiliary file. The before-commit hook must open and |
|
142
|
read that file if it wants access to the commit information. |
|
143
|
|
|
144
|
## Commit-Msg Hooks |
|
145
|
|
|
146
|
* Commit-msg hooks are not yet implemented. |
|
147
|
|
|
148
|
* The commit-msg hooks run during "fossil commit" after the check-in |
|
149
|
message has been entered by the user. The "%A" argument to the |
|
150
|
commit-msg hook is the text of the commit message. The intent |
|
151
|
of the commit-msg hook is to validate the text of the commit |
|
152
|
message to (for example) check for typos or ensure that it |
|
153
|
conforms to standards. |
|
154
|
|
|
155
|
* If any commit-msg hook returns a non-zero exit code, then |
|
156
|
the commit is abandoned. All |
|
157
|
commit-msg hooks must exit(0) in order for the commit to |
|
158
|
proceed. |
|
159
|
|
|
160
|
* Commit-msg hooks are advisory only. Each developer is in total |
|
161
|
control of the local repository and can easily bypass the hooks |
|
162
|
to cause a non-conforming checkin to be committed. |
|
163
|
|