about summary refs log tree commit diff
path: root/guix/forge/forge.scm
diff options
context:
space:
mode:
Diffstat (limited to 'guix/forge/forge.scm')
-rw-r--r--guix/forge/forge.scm106
1 files changed, 70 insertions, 36 deletions
diff --git a/guix/forge/forge.scm b/guix/forge/forge.scm
index 20d534c..49cc0d5 100644
--- a/guix/forge/forge.scm
+++ b/guix/forge/forge.scm
@@ -51,6 +51,7 @@
             forge-configuration?
             forge-configuration-web-domain
             forge-configuration-tissue-web-domain
+            forge-configuration-websites-directory
             forge-configuration-web-root
             forge-configuration-projects
             forge-project
@@ -61,8 +62,8 @@
             forge-project-repository
             forge-project-repository-branch
             forge-project-web-domain
-            forge-project-website-directory
             forge-project-tissue?
+            forge-project-website-ci-job
             forge-project-ci-jobs
             forge-project-ci-jobs-trigger
             forge-project-parallel-ci-job-runs
@@ -89,10 +90,12 @@
                (default #f))
   (web-domain forge-project-web-domain
               (default #f))
-  (website-directory forge-project-website-directory
-                     (default #f))
   (tissue? forge-project-tissue?
            (default #f))
+  (website-ci-job forge-project-website-ci-job
+                  ;; TODO: Add default website builder.
+                  (default #f)
+                  (thunked))
   (ci-jobs forge-project-ci-jobs
            (default '()) (thunked))
   (ci-jobs-trigger forge-project-ci-jobs-trigger ; one of 'post-receive-hook, 'cron, 'webhook
@@ -113,6 +116,8 @@
   (web-domain forge-configuration-web-domain)
   (tissue-web-domain forge-configuration-tissue-web-domain
                      (default #f))
+  (websites-directory forge-configuration-websites-directory
+                      (default "/srv/http/forge"))
   (web-root forge-configuration-web-root
             (default (computed-file "forge-web-root"
                                     (forge-web-root-gexp this-forge-configuration)))
@@ -185,12 +190,11 @@
                 (list (forge-project-user project)
                       (forge-project-repository project)
                       (forge-project-description project)
-                      (forge-project-website-directory project)
                       (program-file
                        (string-append (forge-project-name project)
                                       "-post-receive-hook")
                        (ci-jobs-trigger-gexp
-                        (forge-project-ci-jobs project)
+                        (forge-project-all-ci-jobs project config)
                         #:reason "post-receive hook"))
                       (forge-project-ci-jobs-trigger project)))
               (forge-configuration-projects config))))
@@ -205,8 +209,14 @@
                                   '(regular directory)))
                       #:directories? #t))
         
+        ;; Set ownership of forge websites directory.
+        (let ((user (getpw "laminar")))
+          (chown #$(forge-configuration-websites-directory config)
+                 (passwd:uid user)
+                 (passwd:gid user)))
+
         (for-each (match-lambda
-                    ((username repository description website-directory ci-jobs-trigger ci-jobs-trigger-type)
+                    ((username repository description ci-jobs-trigger ci-jobs-trigger-type)
                      ;; For local repositories only
                      (when (string-prefix? "/" repository)
                        ;; Set description.
@@ -228,12 +238,7 @@
                        (let ((hook-link (string-append repository "/hooks/post-receive")))
                          (when (file-exists? hook-link)
                            (delete-file hook-link))
-                         (symlink ci-jobs-trigger hook-link)))
-                     ;; Set ownership of website directory.
-                     (when website-directory
-                       (let ((user (getpw "laminar")))
-                         (chown (dirname website-directory)
-                                (passwd:uid user) (passwd:gid user))))))
+                         (symlink ci-jobs-trigger hook-link)))))
                   '#$projects))))
 
 (define (import-module? name)
@@ -485,36 +490,51 @@ that were built."
                                           (package-channels pkg))))))))
                 inferior))))))))
 
+(define (switch-symlinks-gexp link target)
+  "Return a G-expression that links @var{link} to @var{target}. @var{target} is a
+singleton list of targets as returned by @code{guix-channel-job-gexp}."
+  (with-imported-modules '((guix build utils))
+    #~(begin
+        (use-modules (guix build utils)
+                     (ice-9 match))
+
+        (switch-symlinks #$link
+                         (match #$target
+                           ((target) target))))))
+
 (define (forge-nginx-server-blocks config)
   "Return list of @code{<nginx-server-configuration>} extensions for
 forge configuration @var{config}."
   (cons (nginx-server-configuration
           (server-name (list (forge-configuration-web-domain config)))
           (root (forge-configuration-web-root config))
+          ;; Serve HTML files without extension.
+          (try-files (list "$uri" "$uri.html" "$uri/index.html" "=404"))
           (locations
-           ;; Configure location blocks for projects that have a website
-           ;; directory but no web domain.
+           ;; Configure location blocks for projects that have no web domain.
            (filter-map (lambda (project)
                          (match-record project <forge-project>
-                           (name web-domain website-directory)
+                           (name web-domain)
                            (and (not web-domain)
-                                website-directory
                                 (nginx-location-configuration
                                   (uri (string-append "/" name "/"))
                                   (body
-                                   (list (string-append "alias "
-                                                        (file-name-as-directory website-directory)
+                                   (list (string-append "root "
+                                                        (forge-configuration-websites-directory config)
                                                         ";")))))))
                        (forge-configuration-projects config))))
-        ;; Configure nginx server blocks for projects that have a web domain and
-        ;; a website directory.
+        ;; Configure nginx server blocks for projects that have a web domain.
         (filter-map (match-record-lambda <forge-project>
-                      (web-domain website-directory)
+                      (name web-domain)
                       (and web-domain
-                           website-directory
                            (nginx-server-configuration
                              (server-name (list web-domain))
-                             (root website-directory))))
+                             (root (string-append (forge-configuration-websites-directory config)
+                                                  "/"
+                                                  name))
+                             ;; Serve HTML files without extension.
+                             (try-files (list "$uri" "$uri.html"
+                                              "$uri/index.html" "=404")))))
                     (forge-configuration-projects config))))
 
 (define (forge-tissue-hosts config)
@@ -540,17 +560,31 @@ forge configuration @var{config}."
                               projects))))
           (list))))
 
+(define (forge-project-all-ci-jobs project config)
+  "Return list of all CI jobs for @var{project} in forge configuration
+@var{config}."
+  ;; Add project context to CI jobs.
+  (map (lambda (job)
+         (forge-laminar-job
+          (inherit job)
+          (contexts (cons (forge-project-name project)
+                          (forge-laminar-job-contexts job)))))
+       ;; Prepend website CI job to the other CI jobs.
+       (if (forge-project-website-ci-job project)
+           (cons (forge-laminar-job
+                  (inherit (forge-project-website-ci-job project))
+                  (run (switch-symlinks-gexp
+                        (string-append (forge-configuration-websites-directory config)
+                                       "/"
+                                       (forge-project-name project))
+                        (forge-laminar-job-run (forge-project-website-ci-job project)))))
+                 (forge-project-ci-jobs project))
+           (forge-project-ci-jobs project))))
+
 (define (forge-ci-jobs config)
   "Return list of CI jobs for forge configuration @var{config}. Each
 value of the returned list is a @code{<forge-laminar-job>} object."
-  (append-map (lambda (project)
-                ;; Add project context to CI jobs.
-                (map (lambda (job)
-                       (forge-laminar-job
-                        (inherit job)
-                        (contexts (cons (forge-project-name project)
-                                        (forge-laminar-job-contexts job)))))
-                     (forge-project-ci-jobs project)))
+  (append-map (cut forge-project-all-ci-jobs <> config)
               (forge-configuration-projects config)))
 
 (define (forge-ci-job-contexts config)
@@ -568,7 +602,7 @@ value of the returned list is a @code{<forge-laminar-job>} object."
 @var{config}. Each element of the returned list is a
 @code{<forge-laminar-group>} object."
   (filter-map (lambda (project)
-                (match (forge-project-ci-jobs project)
+                (match (forge-project-all-ci-jobs project config)
                   (() #f)
                   ((job) #f)
                   (jobs
@@ -597,13 +631,13 @@ mcron job specification."
                 (and (eq? (forge-project-ci-jobs-trigger project)
                           'cron)
                      (any forge-laminar-job-trigger?
-                          (forge-project-ci-jobs project))
+                          (forge-project-all-ci-jobs project config))
                      #~(job '(next-day)
                             #$(program-file
                                (string-append (forge-project-name project)
                                               "-cron-job")
                                (ci-jobs-trigger-gexp
-                                (forge-project-ci-jobs project)
+                                (forge-project-all-ci-jobs project config)
                                 #:reason "Cron job"))
                             #:user "laminar")))
               (forge-configuration-projects config)))
@@ -615,11 +649,11 @@ value is a list of @code{<webhook-hook>} objects."
                 (and (eq? (forge-project-ci-jobs-trigger project)
                           'webhook)
                      (any forge-laminar-job-trigger?
-                          (forge-project-ci-jobs project))
+                          (forge-project-all-ci-jobs project config))
                      (webhook-hook
                       (id (forge-project-name project))
                       (run (ci-jobs-trigger-gexp
-                            (forge-project-ci-jobs project)
+                            (forge-project-all-ci-jobs project config)
                             #:reason "Webhook")))))
               (forge-configuration-projects config)))