aboutsummaryrefslogtreecommitdiff
path: root/forge/forge.scm
diff options
context:
space:
mode:
authorArun Isaac2021-12-21 00:17:46 +0530
committerArun Isaac2021-12-21 00:17:46 +0530
commit45edabc3e8206caf50c7d1b105ebfeec8a82c4e4 (patch)
tree0fde4b038f0da753e768dad9c75f15a5a7b765b8 /forge/forge.scm
downloadguix-forge-45edabc3e8206caf50c7d1b105ebfeec8a82c4e4.tar.gz
guix-forge-45edabc3e8206caf50c7d1b105ebfeec8a82c4e4.tar.lz
guix-forge-45edabc3e8206caf50c7d1b105ebfeec8a82c4e4.zip
Initial commit
Diffstat (limited to 'forge/forge.scm')
-rw-r--r--forge/forge.scm154
1 files changed, 154 insertions, 0 deletions
diff --git a/forge/forge.scm b/forge/forge.scm
new file mode 100644
index 0000000..66113c9
--- /dev/null
+++ b/forge/forge.scm
@@ -0,0 +1,154 @@
+;;; guix-forge --- Guix software forge meta-service
+;;; Copyright © 2021 Arun Isaac <arunisaac@systemreboot.net>
+;;;
+;;; This file is part of guix-forge.
+;;;
+;;; guix-forge is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; guix-forge is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with guix-forge. If not, see
+;;; <https://www.gnu.org/licenses/>.
+
+(define-module (forge forge)
+ #:use-module (gnu)
+ #:use-module (srfi srfi-1)
+ #:use-module (ice-9 match)
+ #:use-module (gnu services mcron)
+ #:use-module (guix records)
+ #:use-module (forge laminar)
+ #:export (forge-service-type
+ forge-configuration
+ forge-configuration-projects
+ forge-project-configuration
+ forge-project-configuration-user
+ forge-project-configuration-repository
+ forge-project-configuration-website-directory
+ forge-project-configuration-ci-jobs))
+
+(define-record-type* <forge-project-configuration>
+ forge-project-configuration make-forge-project-configuration
+ forge-project-configuration?
+ (name forge-project-configuration-name)
+ (user forge-project-configuration-user)
+ (repository forge-project-configuration-repository)
+ (description forge-project-configuration-description
+ (default #f))
+ (website-directory forge-project-configuration-website-directory
+ (default #f))
+ (ci-jobs forge-project-configuration-ci-jobs
+ (default '())))
+
+(define-record-type* <forge-configuration>
+ forge-configuration make-forge-configuration
+ forge-configuration?
+ (projects forge-configuration-projects
+ (default '())))
+
+(define (post-receive-hook project-name ci-jobs)
+ "Return a git post-receive-hook that triggers CI-JOBS."
+ (program-file (string-append project-name "-post-receive-hook")
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+ ;; TODO: Only trigger on updates to the main/master branch.
+ (display "Triggering continuous integration jobs..." (current-error-port))
+ (newline (current-error-port))
+ (apply invoke
+ #$(file-append laminar "/bin/laminarc")
+ "queue" '#$ci-jobs)))))
+
+(define (forge-activation config)
+ (let ((projects
+ (map (lambda (project)
+ (list (forge-project-configuration-user project)
+ (forge-project-configuration-repository project)
+ (forge-project-configuration-description project)
+ (forge-project-configuration-website-directory project)
+ (post-receive-hook
+ (forge-project-configuration-name project)
+ (map guix-laminar-job-name
+ (forge-project-configuration-ci-jobs project)))))
+ (forge-configuration-projects config))))
+ #~(begin
+ (use-modules (rnrs io ports)
+ (srfi srfi-26)
+ (ice-9 match))
+
+ (define (find-regular-files dir)
+ (find-files dir (lambda (file stat)
+ (memq (stat:type stat)
+ '(regular directory)))
+ #:directories? #t))
+
+ (for-each (match-lambda
+ ((username repository description website-directory post-receive-hook)
+ ;; For local repositories only
+ (when (string-prefix? "/" repository)
+ ;; Set description.
+ (when description
+ (call-with-output-file (string-append repository "/description")
+ (cut put-string <> description)))
+ ;; Install post receive hook.
+ (let ((hook-link (string-append repository "/hooks/post-receive")))
+ (when (file-exists? hook-link)
+ (delete-file hook-link))
+ (symlink post-receive-hook hook-link))
+ ;; Set ownership of repository files.
+ (for-each (lambda (file)
+ (let ((user (getpw username)))
+ (chown file (passwd:uid user) (passwd:gid user))))
+ (append (find-regular-files repository))))
+ ;; Set ownership of website directory.
+ (when website-directory
+ (let ((user (getpw "laminar")))
+ (chown website-directory (passwd:uid user) (passwd:gid user))))))
+ '#$projects))))
+
+(define forge-service-type
+ (service-type
+ (name 'forge)
+ (description "Run guix-forge.")
+ (extensions (list (service-extension activation-service-type
+ forge-activation)
+ (service-extension guix-laminar-service-type
+ (lambda (config)
+ (append
+ ;; jobs
+ (append-map forge-project-configuration-ci-jobs
+ (forge-configuration-projects config))
+ ;; groups
+ (filter-map (lambda (project)
+ (match (forge-project-configuration-ci-jobs project)
+ (() #f)
+ ((job) #f)
+ (jobs
+ (guix-laminar-group
+ (name (forge-project-configuration-name project))
+ (regex (string-join (map guix-laminar-job-name jobs)
+ "|"))))))
+ (forge-configuration-projects config)))))
+ ;; Set up cron jobs to trigger CI jobs for remote
+ ;; repositories.
+ ;; TODO: Run CI job only if there are new commits
+ ;; in the remote repository.
+ (service-extension mcron-service-type
+ (lambda (config)
+ (filter-map (lambda (project)
+ (and (not (string-prefix?
+ "/" (forge-project-configuration-repository project)))
+ #~(job '(next-day)
+ #$(post-receive-hook
+ (forge-project-configuration-name project)
+ (map guix-laminar-job-name
+ (forge-project-configuration-ci-jobs project)))
+ #:user "laminar")))
+ (forge-configuration-projects config))))))
+ (default-value (forge-configuration))))