aboutsummaryrefslogtreecommitdiffstats
path: root/roles/git
diff options
context:
space:
mode:
Diffstat (limited to 'roles/git')
-rw-r--r--roles/git/files/cgit/syntax-highlighting.sh75
-rw-r--r--roles/git/files/git-shell-commands/addkey49
-rw-r--r--roles/git/files/git-shell-commands/create42
-rw-r--r--roles/git/files/git-shell-commands/env9
-rw-r--r--roles/git/files/git-shell-commands/help24
-rw-r--r--roles/git/files/git-shell-commands/list22
-rw-r--r--roles/git/files/git-shell-commands/make-private30
-rw-r--r--roles/git/files/git-shell-commands/make-public37
-rw-r--r--roles/git/files/git-shell-commands/no-interactive-login.disabled23
-rw-r--r--roles/git/files/git-shell-commands/set-desc31
-rw-r--r--roles/git/files/git-shell-commands/sync-github103
-rw-r--r--roles/git/handlers/main.yml3
-rw-r--r--roles/git/tasks/main.yml151
-rw-r--r--roles/git/templates/cgit/cgitrc.j2132
-rw-r--r--roles/git/templates/cgit/post-receive.j231
-rw-r--r--roles/git/templates/vars.conf.j211
16 files changed, 773 insertions, 0 deletions
diff --git a/roles/git/files/cgit/syntax-highlighting.sh b/roles/git/files/cgit/syntax-highlighting.sh
new file mode 100644
index 0000000..b3ef6c6
--- /dev/null
+++ b/roles/git/files/cgit/syntax-highlighting.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# Credit:
+# * ArchWiki - cgit
+# https://wiki.archlinux.org/index.php/Cgit
+#
+# Aaron LI
+# 2017-06-19
+#
+
+#
+# This script can be used to implement syntax highlighting in the cgit
+# tree-view by refering to this file with the source-filter or repo.source-
+# filter options in cgitrc.
+#
+# This script requires a shell supporting the ${var##pattern} syntax.
+# It is supported by at least dash and bash, however busybox environments
+# might have to use an external call to sed instead.
+#
+# Note: the highlight command (http://www.andre-simon.de/) uses css for syntax
+# highlighting, so you'll probably want something like the following included
+# in your css file:
+#
+# Style definition file generated by highlight 3.13, http://www.andre-simon.de/
+#
+# body.hl { background-color:#e0eaee; }
+# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New',monospace;}
+# .hl.num { color:#b07e00; }
+# .hl.esc { color:#ff00ff; }
+# .hl.str { color:#bf0303; }
+# .hl.pps { color:#818100; }
+# .hl.slc { color:#838183; font-style:italic; }
+# .hl.com { color:#838183; font-style:italic; }
+# .hl.ppc { color:#008200; }
+# .hl.opt { color:#000000; }
+# .hl.ipl { color:#0057ae; }
+# .hl.lin { color:#555555; }
+# .hl.kwa { color:#000000; font-weight:bold; }
+# .hl.kwb { color:#0057ae; }
+# .hl.kwc { color:#000000; font-weight:bold; }
+# .hl.kwd { color:#010181; }
+#
+#
+# The following environment variables can be used to retrieve the configuration
+# of the repository for which this script is called:
+# CGIT_REPO_URL ( = repo.url setting )
+# CGIT_REPO_NAME ( = repo.name setting )
+# CGIT_REPO_PATH ( = repo.path setting )
+# CGIT_REPO_OWNER ( = repo.owner setting )
+# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
+# CGIT_REPO_SECTION ( = section setting )
+# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
+#
+
+# store filename and extension in local vars
+BASENAME="$1"
+EXTENSION="${BASENAME##*.}"
+
+[ "${BASENAME}" = "${EXTENSION}" ] && EXTENSION=txt
+[ -z "${EXTENSION}" ] && EXTENSION=txt
+
+# map Makefile and Makefile.* to .mk
+[ "${BASENAME%%.*}" = "Makefile" ] && EXTENSION=mk
+
+# WARNING:
+# On DragonFly using Nginx+fcgiwrap, for unknown reason, the `PATH` is set
+# to only `/sbin:/bin:/usr/sbin:/usr/bin`, therefore, the `highlight` cannot
+# be found by default.
+# Explicitly set the `PATH`.
+export PATH="/bin:/usr/bin:/usr/games:/usr/local/bin"
+
+# For version 3
+#exec highlight --force -f -I -O xhtml -S "$EXTENSION" 2>/dev/null
+# Use `--inline-css` to be more colorful without editing cgit's CSS
+exec highlight --force -f -I --inline-css -O xhtml -S "$EXTENSION" 2>/dev/null
diff --git a/roles/git/files/git-shell-commands/addkey b/roles/git/files/git-shell-commands/addkey
new file mode 100644
index 0000000..670fd94
--- /dev/null
+++ b/roles/git/files/git-shell-commands/addkey
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# ~/git-shell-commands/addkey
+#
+# An interactive command to add a new SSH public key to the authorized
+# key list. To ensure the integrity of the authorized_keys file, the
+# script makes sure you've entered a valid key (which must be entered
+# all on one line). For security, the script also disables some SSH
+# options for the key when it adds it.
+#
+# NOTE:
+# This interactive command is NOT allowed through a SSH connection,
+# use `sudo su - git` from other (admin) user instead.
+#
+# Credit:
+# * Hosting an admin-friendly git server with git-shell
+# http://planzero.org/blog/2012/10/24/hosting_an_admin-friendly_git_server_with_git-shell
+#
+# Aaron LI
+# 2017-06-18
+#
+
+if [ -n "${SSH_CONNECTION}" ]; then
+ echo "Sorry, this command is not allowed through a SSH connection"
+ exit 1
+fi
+
+# Read in the SSH key
+echo "Input the SSH public key to be added (ED25519/RSA):"
+read key
+
+# Generate a fingerprint
+fingerprint=$(echo "${key}" | ssh-keygen -lf -)
+
+# Check for errors
+if [ $(echo "${fingerprint}" | egrep -c '(ED25519|RSA)') -eq 0 ]; then
+ # Display the fingerprint error and clean up
+ echo "Invalid key: ${fingerprint}"
+ exit 1
+fi
+
+# Add the key to the authorized keys file and clean up
+[ ! -d "${HOME}/.ssh" ] && mkdir -m 0700 ${HOME}/.ssh
+echo ${key} >> ${HOME}/.ssh/authorized_keys
+chmod 0600 ${HOME}/.ssh/authorized_keys
+
+# Display the fingerprint for reference
+echo "Success! Added a key with the following fingerprint:"
+echo ${fingerprint}
diff --git a/roles/git/files/git-shell-commands/create b/roles/git/files/git-shell-commands/create
new file mode 100644
index 0000000..21cacc1
--- /dev/null
+++ b/roles/git/files/git-shell-commands/create
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# ~/git-shell-commands/create
+#
+# An interactive command to create a new repository. The `.git` extension
+# is automatically added if missing, in order to let `list` command find
+# this repository.
+#
+# Credit:
+# * Hosting an admin-friendly git server with git-shell
+# http://planzero.org/blog/2012/10/24/hosting_an_admin-friendly_git_server_with_git-shell
+#
+# Aaron LI
+# 2017-06-18
+#
+
+if [ $# -eq 0 ]; then
+ echo "Usage: create <project.git> [ description ]"
+ exit 1
+fi
+
+# Set the project name, adding `.git` extension if missing
+project="${1%.[gG][iI][tT]}.git"
+shift
+
+if [ -d "${HOME}/${project}" ]; then
+ echo "ERROR: repository '${project}' already exists!"
+ exit 2
+fi
+
+# Create and initialise the project
+mkdir "${HOME}/${project}" && \
+ cd "${HOME}/${project}" && \
+ git --bare init
+
+description="$@"
+if [ -n "${description}" ]; then
+ echo "${description}" > ${HOME}/${project}/description
+fi
+
+echo "Created Git repository: ${project}"
+echo "Description: $(cat ${HOME}/${project}/description)"
diff --git a/roles/git/files/git-shell-commands/env b/roles/git/files/git-shell-commands/env
new file mode 100644
index 0000000..8b4b496
--- /dev/null
+++ b/roles/git/files/git-shell-commands/env
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# Print current environment.
+#
+# Aaron LI
+# 2017-06-18
+#
+
+/usr/bin/env
diff --git a/roles/git/files/git-shell-commands/help b/roles/git/files/git-shell-commands/help
new file mode 100644
index 0000000..9e37fd2
--- /dev/null
+++ b/roles/git/files/git-shell-commands/help
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# /usr/local/share/git-core/contrib/git-shell-commands/help
+#
+# Aaron LI
+# 2017-06-18
+#
+
+if tty -s; then
+ echo "Run 'help' for help, or 'exit' to leave. Available commands:"
+else
+ echo "Run 'help' for help. Available commands:"
+fi
+
+dir=$(dirname "$0")
+cd "${dir}"
+
+for cmd in *; do
+ case "${cmd}" in
+ help) ;;
+ *.disabled) ;;
+ *) [ -f "${cmd}" ] && [ -x "${cmd}" ] && echo "${cmd}" ;;
+ esac
+done
diff --git a/roles/git/files/git-shell-commands/list b/roles/git/files/git-shell-commands/list
new file mode 100644
index 0000000..2977541
--- /dev/null
+++ b/roles/git/files/git-shell-commands/list
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# /usr/local/share/git-core/contrib/git-shell-commands/list
+#
+# Aaron LI
+# 2017-06-19
+#
+
+. ${HOME}/vars.conf
+
+for repo in $(ls -d *.git); do
+ is_bare_repo=$(git --git-dir="${repo}" rev-parse --is-bare-repository)
+ if [ "${is_bare_repo}" = "true" ]; then
+ echo "* ${repo}"
+ if [ -e "${PUBLIC}/${repo}" ]; then
+ echo " [public]"
+ fi
+ if [ -f "${repo}/description" ]; then
+ echo " $(cat ${repo}/description)"
+ fi
+ fi
+done
diff --git a/roles/git/files/git-shell-commands/make-private b/roles/git/files/git-shell-commands/make-private
new file mode 100644
index 0000000..432d847
--- /dev/null
+++ b/roles/git/files/git-shell-commands/make-private
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Copyright (c) 2017 Aaron LI <aly@aaronly.me>
+# MIT License
+#
+# Turn a public Git repository to be private to `cgit`.
+#
+# 2017-06-19
+#
+
+. ${HOME}/vars.conf
+
+if [ $# -ne 1 ]; then
+ echo "usage: make-private <repository.git>"
+ exit 1
+fi
+
+project="${1%.[gG][iI][tT]}.git"
+
+if [ ! -d "${project}" ]; then
+ echo "ERROR: repository '${project}' not exists!"
+ exit 2
+elif [ -L "${PUBLIC}/${project}" ]; then
+ rm "${PUBLIC}/${project}"
+ echo "Made repository '${project}' private."
+ exit 0
+else
+ echo "Repository '${project}' not public."
+ exit 0
+fi
diff --git a/roles/git/files/git-shell-commands/make-public b/roles/git/files/git-shell-commands/make-public
new file mode 100644
index 0000000..f1dfb1d
--- /dev/null
+++ b/roles/git/files/git-shell-commands/make-public
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Copyright (c) 2017 Aaron LI <aly@aaronly.me>
+# MIT License
+#
+# Make an existing Git repository public by linking it into
+# `repos.public`, which is exported via `cgit`.
+#
+# 2017-06-19
+#
+
+. ${HOME}/vars.conf
+
+if [ $# -ne 1 ]; then
+ echo "usage: make-public <repository.git>"
+ exit 1
+fi
+
+if [ ! -e "${PUBLIC}" ]; then
+ echo "ERROR: public directory '${PUBLIC}' not exists!"
+ exit 1
+fi
+
+project="${1%.[gG][iI][tT]}.git"
+
+if [ ! -d "${project}" ]; then
+ echo "ERROR: repository '${project}' not exists!"
+ exit 3
+elif [ -L "${PUBLIC}/${project}" ]; then
+ echo "Repository '${project}' already made public."
+ exit 0
+else
+ ln -sv ../${project} ${PUBLIC}/${project}
+ echo "Made repository '${project}' public."
+ exit 0
+fi
+
diff --git a/roles/git/files/git-shell-commands/no-interactive-login.disabled b/roles/git/files/git-shell-commands/no-interactive-login.disabled
new file mode 100644
index 0000000..3be7efc
--- /dev/null
+++ b/roles/git/files/git-shell-commands/no-interactive-login.disabled
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# ~/git-shell-commands/no-interactive-login
+#
+# Disable interactive logins, displaying a greeting instead.
+# See git-shell(1)
+#
+# Remove/rename this script to allow interactive logins, e.g.,
+# allow `su - git` to add SSH keys.
+#
+#
+# Aaron LI
+# 2017-06-18
+#
+
+cat <<_EOF_
+Hi ${USER}!
+You've successfully authenticated, but interactive shell
+access is not provided.
+Bye~
+_EOF_
+
+exit 128
diff --git a/roles/git/files/git-shell-commands/set-desc b/roles/git/files/git-shell-commands/set-desc
new file mode 100644
index 0000000..3d0a1be
--- /dev/null
+++ b/roles/git/files/git-shell-commands/set-desc
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# ~/git-shell-commands/set-desc
+#
+# Set the description of an existing Git repository.
+#
+# Aaron LI
+# 2017-08-22
+#
+
+if [ $# -lt 2 ]; then
+ echo "Usage: set-desc <project.git> <description>"
+ exit 1
+fi
+
+# Set the project name, adding `.git` extension if missing
+project="${1%.[gG][iI][tT]}.git"
+shift
+
+if [ ! -d "${HOME}/${project}" ]; then
+ echo "ERROR: repository '${project}' not exists!"
+ exit 2
+fi
+
+description="$@"
+if [ -n "${description}" ]; then
+ echo "${description}" > ${HOME}/${project}/description
+fi
+
+echo "Set description of Git repository: ${project}"
+echo "Description: $(cat ${HOME}/${project}/description)"
diff --git a/roles/git/files/git-shell-commands/sync-github b/roles/git/files/git-shell-commands/sync-github
new file mode 100644
index 0000000..9eef43e
--- /dev/null
+++ b/roles/git/files/git-shell-commands/sync-github
@@ -0,0 +1,103 @@
+#!/bin/sh
+#
+# Copyright (c) 2017 Aaron LI <aly@aaronly.me>
+# MIT License
+#
+# Sync public repositories to GitHub.
+#
+# 2017-06-25
+#
+
+. ${HOME}/vars.conf
+
+# Return 0 if the GitHub repository exists
+has_github_repo() {
+ local repo url
+ repo=$(basename $1)
+ repo="${repo%.git}"
+ url="${GITHUB_API}/repos/${GITHUB_USER}/${repo}"
+ echo "Check existence on GitHub: ${url}"
+ curl -s ${url} | grep -q '"owner"'
+}
+
+
+# Add the "github" remote if not exists
+add_remote_github() {
+ local gitdir_ repo url ret
+ gitdir_="$1"
+ url=$(git --git-dir="${gitdir_}" remote get-url github 2>&1)
+ ret=$?
+ if [ ${ret} -eq 0 ]; then
+ # Already has the "github" remote
+ echo "Remote 'github': ${url}"
+ else
+ repo=$(basename ${gitdir_})
+ url="${GITHUB_URL}:${GITHUB_USER}/${repo}"
+ git --git-dir="${gitdir_}" remote add github ${url}
+ echo "Added remote 'github': ${url}"
+ git --git-dir="${gitdir_}" remote update github
+ fi
+}
+
+
+# Check whether the repository needs push to remote "github";
+# Return 0 if needs push.
+#
+# Credit:
+# * Check if pull needed in Git
+# https://stackoverflow.com/a/3278427/4856091
+# * List Git commits not pushed to the origin yet
+# https://stackoverflow.com/a/3080554/4856091
+#
+need_push_github() {
+ local gitdir_ unpushed
+ gitdir_="$1"
+ unpushed=$(git --git-dir="${gitdir_}" \
+ log --oneline github/master..master | wc -l)
+ if [ ${unpushed} -eq 0 ]; then
+ echo "Already up-to-date" && false
+ else
+ echo "${unpushed} commits need push" && true
+ fi
+}
+
+
+if [ $# -eq 0 ]; then
+ cat <<_EOF_
+usage:
+ sync-github <repo.git> ...
+ sync-github @<repo_dir>
+
+e.g.,
+ sync-github @${PUBLIC}
+_EOF_
+ exit 1
+fi
+
+
+if [ "$(echo $1 | cut -c1)" = "@" ]; then
+ REPO_DIR="${1#@}"
+ REPOS=$(ls -d ${REPO_DIR}/*.git)
+else
+ REPOS="$@"
+fi
+
+echo "=== Selected Repositories ==="
+for repo in ${REPOS}; do
+ repo2="${repo%.[gG][iI][tT]}.git"
+ echo "* ${repo2}"
+done
+
+for repo in ${REPOS}; do
+ repo2="${repo%.[gG][iI][tT]}.git"
+ echo "=== Sync Repository: ${repo2} ==="
+ if ! has_github_repo ${repo2}; then
+ echo "WARNING: no such repo on GitHub: ${repo2}"
+ continue
+ fi
+ add_remote_github ${repo2}
+ if need_push_github ${repo2}; then
+ echo "Push commits to GitHub ..."
+ git --git-dir="${repo2}" push --mirror github
+ fi
+done
diff --git a/roles/git/handlers/main.yml b/roles/git/handlers/main.yml
new file mode 100644
index 0000000..6e08be5
--- /dev/null
+++ b/roles/git/handlers/main.yml
@@ -0,0 +1,3 @@
+---
+- name: restart-cgit
+ command: service uwsgi restart cgit
diff --git a/roles/git/tasks/main.yml b/roles/git/tasks/main.yml
new file mode 100644
index 0000000..90eba2b
--- /dev/null
+++ b/roles/git/tasks/main.yml
@@ -0,0 +1,151 @@
+---
+- name: install packages
+ pkgng:
+ name: "{{ item }}"
+ state: present
+ with_items:
+ - git
+ - cgit
+ - uwsgi-py36
+
+- name: check user group existence
+ command: pw groupshow {{ git.user.name }}
+ register: pw_cmd
+ ignore_errors: true
+ changed_when: false
+
+- name: create user group
+ command: pw groupadd {{ git.user.name }} -g {{ git.user.id }}
+ when: pw_cmd.rc != 0
+
+- name: check user existence
+ command: pw usershow {{ git.user.name }}
+ register: pw_cmd
+ ignore_errors: true
+ changed_when: false
+
+- name: create user
+ command: >
+ pw useradd {{ git.user.name }}
+ -u {{ git.user.id }} -g {{ git.user.name }}
+ -d {{ git.user.home }} -m -M 0700
+ -s {{ git.user.shell }}
+ -c "Git Repositories Owner"
+ when: pw_cmd.rc != 0
+
+- name: add ssh keys
+ authorized_key:
+ user: "{{ git.user.name }}"
+ state: present
+ key: "{{ lookup('file', item) }}"
+ with_fileglob:
+ - "{{ git.user.ssh_keydir }}/*.pub"
+
+- name: generate vars.conf file
+ template:
+ src: vars.conf.j2
+ dest: "{{ git.user.home }}/vars.conf"
+
+- name: copy git-shell commands
+ copy:
+ src: git-shell-commands/ # trailing '/' -> directory contents
+ dest: "{{ git.user.home }}/git-shell-commands/"
+
+- name: add execution permission to git-shell commands
+ file:
+ path: "{{ git.user.home }}/git-shell-commands"
+ mode: 0755
+ recurse: true
+
+- name: (local) github sync - check ssh key existence
+ become: false
+ stat:
+ path: "{{ playbook_dir }}/private/git/{{ git.github.keyname }}"
+ delegate_to: localhost
+ register: stat_result
+
+- name: (local) github sync - generate new ssh key pair
+ become: false
+ command: >
+ ssh-keygen -t ed25519 -C "git:github-sync" -N ""
+ -f "{{ playbook_dir }}/private/git/{{ git.github.keyname }}"
+ delegate_to: localhost
+ when: not stat_result.stat.exists
+
+- name: github sync - create .ssh directory on the server
+ file:
+ path: "{{ git.user.home }}/.ssh"
+ state: directory
+ owner: "{{ git.user.name }}"
+ group: "{{ git.user.name }}"
+ mode: 0700
+
+- name: github sync - copy public key to the server
+ copy:
+ src: "{{ playbook_dir }}/private/git/{{ git.github.keyname }}"
+ dest: "{{ git.user.home }}/.ssh/id_{{ git.github.keytype }}"
+ owner: "{{ git.user.name }}"
+ mode: 0400
+
+- name: create directory for linking public repos
+ file:
+ path: "{{ git.user.home }}/{{ git.public_dir }}"
+ state: directory
+ owner: "{{ git.user.name }}"
+ group: "{{ git.user.name }}"
+
+#
+# cgit
+#
+
+- name: cgit - create root directory
+ file:
+ path: "{{ git.cgit.root }}"
+ state: directory
+
+- name: cgit - create static directory (allow git checkout)
+ file:
+ path: "{{ git.cgit.root }}/static"
+ state: directory
+ owner: "{{ git.user.name }}"
+ group: "{{ git.user.name }}"
+
+- name: cgit - generate config file
+ template:
+ src: cgit/cgitrc.j2
+ dest: "{{ git.cgit.root }}/cgitrc"
+ notify: restart-cgit
+
+- name: cgit - create static repo
+ become_user: "{{ git.user.name }}"
+ command: >
+ ./git-shell-commands/create
+ {{ git.cgit.static_repo }}
+ "cgit static resources repo"
+ args:
+ chdir: "{{ git.user.home }}"
+ creates: "{{ git.user.home }}/{{ git.cgit.static_repo }}"
+
+- name: cgit - add post-receive hook to the static repo
+ template:
+ src: cgit/post-receive.j2
+ dest: "{{ git.user.home }}/{{ git.cgit.static_repo }}/hooks/post-receive"
+ owner: "{{ git.user.name }}"
+ mode: 0755
+
+- name: cgit - setup with uwsgi in rc.conf
+ blockinfile:
+ path: /etc/rc.conf
+ marker: "# {mark} ANSIBLE MANAGED - uwsgi/cgit"
+ block: |
+ uwsgi_profiles="${uwsgi_profiles} cgit"
+ uwsgi_cgit_uid="git"
+ uwsgi_cgit_gid="git"
+ uwsgi_cgit_flags="-L --log-reopen --logfile-chown --cgi /usr/local/www/cgit/cgit.cgi --env CGIT_CONFIG={{ git.cgit.root }}/cgitrc"
+ notify: restart-cgit
+
+- name: enable and start uwsgi
+ command: rcenable uwsgi
+
+- name: start cgit
+ command: service uwsgi start cgit
diff --git a/roles/git/templates/cgit/cgitrc.j2 b/roles/git/templates/cgit/cgitrc.j2
new file mode 100644
index 0000000..f0d83fc
--- /dev/null
+++ b/roles/git/templates/cgit/cgitrc.j2
@@ -0,0 +1,132 @@
+#
+# {{ git.cgit.root }}/cgitrc
+# Configuration file for `cgit` served at `code.aaronly.me`.
+# See https://git.zx2c4.com/cgit/tree/cgitrc.5.txt
+#
+# Aaron LI
+# 2017-06-19
+#
+
+# Title and heading of the index page
+root-title=Projects from Aaron LI
+
+# Subheading of the index page
+root-desc=The journey is long, but I shall search high and low.
+
+# More information on the index page
+#root-readme={{ git.cgit.root }}/static/about.html
+
+# File containing the footer that will be included verbatim at
+# the bottom of all pages
+footer={{ git.cgit.root }}/static/footer.html
+
+
+##
+## Static resources (URL configured via Nginx))
+##
+
+css=/static/cgit.css
+logo=/static/logo.png
+favicon=/static/favicon.ico
+
+
+##
+## Settings
+##
+
+# Root URL for all cgit links
+virtual-root=/
+
+# Set default clone URL using macro
+clone-url=https://git.{{ domains[0].name }}/$CGIT_REPO_URL
+
+# Allow HTTP transport git clone
+enable-http-clone=1
+
+# Do NOT show owner on index page
+enable-index-owner=0
+
+# Show extra links for each repository on the index page
+enable-index-links=1
+
+# Enable ASCII art commit history graph on the log pages
+enable-commit-graph=1
+
+# Show number of affected files per commit on the log pages
+enable-log-filecount=1
+
+# Show number of added/removed lines per commit on the log pages
+enable-log-linecount=1
+
+# Sort branches by date
+branch-sort=age
+
+# Enable statistics per week, month, and quarter
+max-stats=quarter
+
+# Allow download of tar.bz2
+snapshots=tar.bz2
+
+
+##
+## List of common mimetypes
+##
+
+mimetype.gif=image/gif
+mimetype.html=text/html
+mimetype.jpg=image/jpeg
+mimetype.jpeg=image/jpeg
+mimetype.pdf=application/pdf
+mimetype.png=image/png
+mimetype.svg=image/svg+xml
+
+# Highlight source code
+# Requires `py36-pygments` package
+#source-filter=/usr/local/lib/cgit/filters/syntax-highlighting.py
+# Requires `highlight` package
+source-filter={{ git.cgit.root }}/syntax-highlighting.sh
+
+# Format markdown, restructuredtext, manpages, text files, and
+# html files through the right converters
+about-filter=/usr/local/lib/cgit/filters/about-formatting.sh
+
+# Search for these files in the root of the default branch of
+# repositories for coming up with the about page:
+readme=:README.md
+readme=:readme.md
+readme=:README.mkd
+readme=:readme.mkd
+readme=:README.rst
+readme=:readme.rst
+readme=:README.html
+readme=:readme.html
+readme=:README.htm
+readme=:readme.htm
+readme=:README.txt
+readme=:readme.txt
+readme=:README
+readme=:readme
+readme=:INSTALL.md
+readme=:install.md
+readme=:INSTALL.mkd
+readme=:install.mkd
+readme=:INSTALL.rst
+readme=:install.rst
+readme=:INSTALL.html
+readme=:install.html
+readme=:INSTALL.htm
+readme=:install.htm
+readme=:INSTALL.txt
+readme=:install.txt
+readme=:INSTALL
+readme=:install
+
+
+##
+## Repositories
+##
+
+# NOTE: only the global settings before this directive will be
+# applied to each repository.
+scan-path={{ git.user.home }}/{{ git.public_dir }}
+
diff --git a/roles/git/templates/cgit/post-receive.j2 b/roles/git/templates/cgit/post-receive.j2
new file mode 100644
index 0000000..14b455a
--- /dev/null
+++ b/roles/git/templates/cgit/post-receive.j2
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# post-receive hook for the cgit-static.git repo to checkout the
+# resources upon push, a.k.a., deploy on push.
+#
+# Aaron LI
+# 2018-04-18
+#
+
+GIT_DIR="{{ git.user.home }}/{{ git.cgit.static_repo }}/"
+TARGET="{{ git.cgit.root }}/static/"
+TARGET_BRANCH="master"
+
+while read oldrev newrev refname; do
+ branch=$(git rev-parse --symbolic --abbrev-ref ${refname})
+ if [ -n "${branch}" ] && [ "${branch}" = "${TARGET_BRANCH}" ]; then
+ echo "Deploying cgit static resources ..."
+ git --work-tree=${TARGET} --git-dir=${GIT_DIR} \
+ checkout ${TARGET_BRANCH} -f
+
+ NOW=$(date +"%Y%m%d-%H%M")
+ git tag release_${NOW} ${TARGET_BRANCH}
+
+ echo " +==============================="
+ echo " | DEPLOYMENT COMPLETED"
+ echo " | Target branch: ${TARGET_BRANCH}"
+ echo " | Target folder: ${TARGET}"
+ echo " | Tag name : release_${NOW}"
+ echo " +==============================="
+ fi
+done
diff --git a/roles/git/templates/vars.conf.j2 b/roles/git/templates/vars.conf.j2
new file mode 100644
index 0000000..1c9fe9c
--- /dev/null
+++ b/roles/git/templates/vars.conf.j2
@@ -0,0 +1,11 @@
+#
+# Settings shared across git-shell-commands scripts
+#
+
+# Directory to be exported by `cgit`
+PUBLIC="{{ git.user.home }}/{{ git.public_dir }}"
+
+# Settings for syncing repositories to GitHub
+GITHUB_USER="{{ git.github.user }}"
+GITHUB_API="{{ git.github.api }}"
+GITHUB_URL="{{ git.github.url }}"