685c1b59de59f31dc996716ff487b49eba4f308c
[goals.git] / libguestfs_upstream.ml
1 (* This goal script is responsible for:
2  *  - testing each new commit to the libguestfs source repo
3  *  - checking for new upstream releases of libguestfs
4  *  - testing new upstream releases
5  *  - packaging them as a source tarball
6  *  - testing the source tarball on a variety of systems
7  *  - if all the above works, uploading the external website
8  * Note this doesn't build the Fedora releases.  See 'libguestfs_fedora.ml'.
9  *)
10
11 open Goaljobs
12 open Printf
13 open Config
14 open Libguestfs
15
16 (* Enable debugging. *)
17 let () =
18   Unix.putenv "LIBGUESTFS_DEBUG" "1";
19   Unix.putenv "LIBGUESTFS_TRACE" "1"
20
21 (* Log program output. *)
22 let from = "rjones@redhat.com"
23 let to_ = "rjones@redhat.com"
24 (*
25 let logfile = log_program_output ()
26 let () = eprintf "logging to %s\n%!" logfile
27 *)
28
29 let package = "libguestfs"
30
31 (* Goal: the website has been updated to 'version'. *)
32 let rec goal website_updated version =
33   target (url_exists version.url &&
34             (if version.is_stable then
35                url_exists version.python_url
36              else true)
37          );
38
39   require (tarball_created version);
40   require (tarball_tested version);
41   if version.is_stable then
42     require (tarball_signed version);
43
44   (* Python sdists only generated for stable releases. *)
45   if version.is_stable then (
46     require (python_tarball_created version);
47     require (python_tarball_tested version)
48   );
49
50   (* We only update the website for the development releases. *)
51   if not version.is_stable then
52     require (website_built version);
53
54   require (website_checked_in version);
55   if version.is_stable then
56     require (python_website_checked_in version);
57   require (website_rsync_done version)
58
59 (* Goal: website has been rsync'd. *)
60 and website_rsync_done version =
61   target (url_contains_string "http://libguestfs.org" version.version &&
62           url_exists version.url);
63
64   sh "
65     cd %s
66     ./.rsync
67   " websites_repo
68
69 (* Goal: Tarball added to repository and checked in. *)
70 and website_checked_in version =
71   let key = sprintf "libguestfs_website_checked_in_%s" version.version in
72   target (memory_exists key);
73   onrun (fun () -> memory_set key "1");
74
75   require (tarball_created version);
76   require (tarball_tested version);
77   if version.is_stable then
78     require (tarball_signed version);
79
80   sh "
81     cd %s
82     cp %s/tarballs/%s %s
83     if %b; then cp %s/tarballs/%s.sig %s.sig; fi
84     git add %s
85     cd %s
86     git add *.txt *.html
87     cd %s
88     git commit -m \"Version %s\"
89   " libguestfs_download_repo
90     buildtmp version.tarball version.urlpath
91     version.is_stable buildtmp version.tarball version.urlpath
92     version.urlpath
93     libguestfs_website_repo
94     websites_repo
95     version.version
96
97 (* Goal: website (local copy) has been built. *)
98 and website_built version =
99   let index_file = sprintf "%s/index.html" libguestfs_website_repo in
100   target (file_contains_string index_file version.version);
101
102   require (tarball_created version);
103   require (tarball_tested version);
104
105   (* We should only update the website on development releases. *)
106   assert (not version.is_stable);
107
108   sh "
109     tar zxf %s/tarballs/%s
110     cd %s
111
112     echo %s > localconfigure
113     chmod +x localconfigure
114     echo %s > localenv
115
116     ./localconfigure
117     make V=1
118     make maintainer-upload-website WEBSITESDIR=%s
119   " buildtmp version.tarball
120     version.package_version
121     (quote (libguestfs_localconfigure `Tarball))
122     (quote (libguestfs_localenv (supermin version)))
123     (quote websites_repo)
124
125 (* Goal: for stable versions, the tarball must be signed. *)
126 and tarball_signed version =
127   let tar_file = sprintf "%s/tarballs/%s" buildtmp version.tarball in
128   let sig_file = tar_file ^ ".sig" in
129   target (file_exists sig_file);
130
131   require (tarball_created version);
132
133   sh "sign-tarball %s" tar_file
134
135 (* Goal: the tarball has passed the required set of tests before
136  * a release is allowed.
137  *)
138 and tarball_tested version =
139   let key = sprintf "libguestfs_tarball_tested_%s" version.version in
140   target (memory_exists key);
141   onrun (fun () -> memory_set key "1");
142
143   require (tarball_created version);
144
145   sh "
146     tar zxf %s/tarballs/%s
147     cd %s
148
149     echo %s > localconfigure
150     chmod +x localconfigure
151     echo %s > localenv
152
153     ./localconfigure
154     make V=1
155     if ! make check-release; then
156       for f in `find -name test-suite.log | xargs grep -l ^FAIL:`; do
157         echo \"*** $f ***\"
158         cat $f
159       done
160       exit 1
161     fi
162   " buildtmp version.tarball
163     version.package_version
164     (quote (libguestfs_localconfigure `Tarball))
165     (quote (libguestfs_localenv (supermin version)))
166
167 (* Goal: the tarball has been created from git. *)
168 and tarball_created version =
169   let filename = sprintf "%s/tarballs/%s" buildtmp version.tarball in
170   target (file_exists filename);
171
172   require (repo_up_to_date version.branch);
173
174   let repodir = sprintf "%s/repos/%s-%s" buildtmp package version.branch in
175
176   (* Branches <= 1.32 are tagged with "1.32.11",
177    * branches >= 1.33 are tagged with "v1.33.11".
178    *)
179   let version_tag =
180     if version.minor >= 33 then "v" ^ version.version
181     else version.version in
182
183   sh "
184     cp -a %s libguestfs
185     cd libguestfs
186     git reset --hard %s
187
188     echo %s > localconfigure
189     chmod +x localconfigure
190     echo %s > localenv
191
192     ./localconfigure
193
194     # Ensure the po-docs are updated.  Grrr this is ugly ...
195     make ||:
196     rm po-docs/podfiles
197     make -C po-docs update-po
198
199     make V=1
200     make dist
201
202     # Ensure redhat hardening flags didn't leak into the tarball.
203     # https://bugzilla.redhat.com/show_bug.cgi?id=1214506
204     if zcat %s | grep -q redhat-hardened; then exit 1; fi
205
206     mv %s %s/tarballs/%s
207   " repodir
208     version_tag
209     (quote (libguestfs_localconfigure `Git))
210     (quote (libguestfs_localenv (supermin version)))
211     version.tarball
212     version.tarball buildtmp version.tarball
213
214 (* Goal: test a commit. *)
215 and commit_tested branch commit =
216   onfail (
217     fun _ ->
218       let subject = sprintf "goal: %s: FAILED" goalname in
219       mailto ~from ~subject (*~attach:[logfile]*) to_
220   );
221
222   let key = sprintf "libguestfs_commit_tested_%s" commit in
223   target (memory_exists key);
224   onrun (fun () -> memory_set key "1");
225
226   require (repo_up_to_date branch);
227
228   let repodir = sprintf "%s/repos/%s-%s" buildtmp package branch in
229
230   sh "
231     cp -a %s libguestfs
232     cd libguestfs
233     git reset --hard %s
234
235     echo %s > localconfigure
236     chmod +x localconfigure
237     echo %s > localenv
238
239     ./localconfigure
240     make V=1
241     if ! make check-release; then
242       for f in `find -name test-suite.log | xargs grep -l ^FAIL:`; do
243         echo \"*** $f ***\"
244         cat $f
245       done
246       exit 1
247     fi
248   " repodir
249     commit
250     (quote (libguestfs_localconfigure `Git))
251     (quote (libguestfs_localenv None))
252
253 and repo_up_to_date branch =
254   git_force branch
255
256 (* Goals for Python sdists. *)
257 and python_website_checked_in version =
258   let key = sprintf "libguestfs_python_website_checked_in_%s" version.version in
259   target (memory_exists key);
260   onrun (fun () -> memory_set key "1");
261
262   require (python_tarball_created version);
263   require (python_tarball_tested version);
264
265   sh "
266     cd %s
267     cp %s/tarballs/%s %s
268     git add %s
269     git commit -m \"Python sdist version %s\"
270   " libguestfs_download_repo
271     buildtmp version.python_tarball version.python_urlpath
272     version.python_urlpath
273     version.version
274
275 and python_tarball_tested version =
276   let key = sprintf "libguestfs_python_tarball_tested_%s" version.version in
277   target (memory_exists key);
278   onrun (fun () -> memory_set key "1");
279
280   require (python_tarball_created version);
281
282   sh "
283     virtualenv venv
284     source ./venv/bin/activate
285     pip install %s/tarballs/%s
286   " buildtmp version.python_tarball
287
288 and python_tarball_created version =
289   let filename = sprintf "%s/tarballs/%s" buildtmp version.python_tarball in
290   target (file_exists filename);
291
292   require (tarball_created version);
293
294   sh "
295     tar zxf %s/tarballs/%s
296     cd %s
297
298     echo %s > localconfigure
299     chmod +x localconfigure
300     echo %s > localenv
301
302     ./localconfigure
303     make V=1
304     make -C python sdist
305     cp python/dist/%s %s
306   " buildtmp version.tarball
307     version.package_version
308     (quote (libguestfs_localconfigure `Tarball))
309     (quote (libguestfs_localenv (supermin version)))
310     version.python_tarball filename
311
312 let () =
313   (* Add a periodic job to check for new git commits and test them. *)
314   every libguestfs_query_mins minutes ~name:"new libguestfs commit" (
315     fun () ->
316       require (repo_up_to_date "master");
317       let commit = git_latest_commit "master" in
318       require (commit_tested "master" commit);
319   );
320
321   (* Periodic job to build new tarballs. *)
322   every libguestfs_query_mins minutes ~name:"new libguestfs version" (
323     fun () ->
324       require (repo_up_to_date "master");
325       let version = git_latest_version "master" in
326       require (website_updated version)
327   )
328
329 (* Allow these jobs to run from the command line. *)
330 let () =
331   publish "commit" (
332     function
333     | [commit] -> require (commit_tested "master" commit)
334     | [branch; commit] -> require (commit_tested branch commit)
335     | _ ->
336       failwith "use './libguestfs_upstream commit [<branch>] <commit>'"
337   );
338   publish "release" (
339     function
340     | [version] -> require (website_updated (vernames version))
341     | _ ->
342       failwith "use './libguestfs_upstream release <version>'"
343   )