Initial commit
Add default gerrit projects config for sandbox

Related-PROD: RE-336

Change-Id: I788bb9317005b8094bfbcde75da77a993e0404cb
diff --git a/tests/jeepyb-verify.py b/tests/jeepyb-verify.py
new file mode 100755
index 0000000..88786d9
--- /dev/null
+++ b/tests/jeepyb-verify.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+
+"""
+Those tests checks the following requirements for the `projects.yaml` file:
+    - Its syntax is valid
+    - Each project definition should consist of the following mandatory parts:
+        * project
+        * description
+      and could contain the following optional parts:
+        * acl-config
+        * upstream
+      No other parts are possible.
+    - All the projects listed in the `projects.yaml` file
+      must be sorted alphabetically.
+"""
+
+import logging
+import os
+import sys
+
+import git
+import jsonschema
+import yaml
+
+
+logging.basicConfig(level=logging.INFO)
+
+# Only lower case letters (a-z), digits (0-9), plus (+) and minus (-)
+# and periods (.).
+# They must be at least two characters long and must start with an
+# alphanumeric character.
+# https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
+# Additionally allow using underline symbol (required by openstack projects)
+
+_PREFIX_PATTERN = '\A([a-z]([a-z]|\d|-)+/)*'
+_NAMES_PATTERN = '([a-zA-Z]|\d)([a-zA-Z]|\d|[+-_.])+\Z'
+PROJECT_NAME_PATTERN = _PREFIX_PATTERN + _NAMES_PATTERN
+
+PROJECT_SCHEMA = {
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type": "array",
+    "items": {
+        "type": "object",
+        "additionalProperties": False,
+        "properties": {
+            "project": {
+                "type": "string",
+                "pattern": PROJECT_NAME_PATTERN
+            },
+            "description": {
+                "type": "string"
+            },
+            "upstream": {
+                "type": "string"
+            },
+
+            "acl-config": {
+                "type": "string"
+            }
+        },
+        "required": ["project", "description"]
+    }
+}
+
+
+def parse_yaml_file(file_path):
+    try:
+        data = yaml.safe_load(open(file_path))
+        if data is None:
+            logging.error("File {0} is empty".format(file_path))
+            sys.exit(1)
+        return data
+    except yaml.YAMLError as exc:
+        msg = "File {0} could not be parsed: {1}".format(file_path, exc)
+        logging.error(msg)
+        sys.exit(1)
+
+
+def validate_data_by_schema(data, file_path):
+    try:
+        jsonschema.validate(data, PROJECT_SCHEMA)
+    except jsonschema.exceptions.ValidationError as exc:
+        raise ValueError(_make_error_message(exc, file_path))
+
+
+def _make_error_message(exc, file_path):
+    value_path = []
+
+    if exc.absolute_path:
+        value_path.extend(exc.absolute_path)
+
+    error_msg = "File '{0}', {1}".format(file_path, exc.message)
+
+    if value_path:
+        value_path = ' -> '.join(map(str, value_path))
+        error_msg = '{0}, value path {1}'.format(error_msg, value_path)
+
+    return error_msg
+
+
+def check_duplicate_projects(data):
+    projects_items = []
+    for item in data:
+        if item['project'] not in projects_items:
+            projects_items.append(item['project'])
+        else:
+            msg = "Project '{0}' is duplicated".format(item['project'])
+            raise ValueError(msg)
+
+
+def check_alphabetical_order(data):
+    for i in range(len(data) - 1):
+        if not data[i]['project'] < data[i + 1]['project']:
+            msg = ("Alphabetical order violation: project '{0}' must be "
+                   "placed after '{1}'".format(data[i]['project'],
+                                               data[i + 1]['project']))
+            raise ValueError(msg)
+
+
+def check_acls_config_path(data):
+    valid = True
+
+    for item in data:
+        acl_config_path = item.get('acl-config')
+        if not acl_config_path:
+            continue
+        # Allow to skip acls/ prefix in acl-config
+        if acl_config_path[:4] != 'acls':
+            acl_config_path = os.path.join('acls', acl_config_path)
+
+        config_path = os.path.join(os.path.abspath(os.curdir),
+                                   acl_config_path)
+        if not os.path.isfile(config_path):
+            logging.error("Config file for project '{0}' is not found "
+                          "at {1}.".format(item.get('project'), config_path))
+            valid = False
+    if not valid:
+        sys.exit(1)
+
+
+def check_upstream_clonable(data):
+    clonable = True
+
+    for item in data:
+        upstream_repo = item.get('upstream')
+        if not upstream_repo:
+            continue
+        logging.info("Checking availability: {0}".format(upstream_repo))
+        try:
+            g = git.cmd.Git()
+            g.ls_remote(upstream_repo)
+        except git.exc.GitCommandError as e:
+            err_msg = ("Unable to clone '{0}':"
+                       "{1}".format(upstream_repo, str(e)))
+            logging.error(err_msg)
+            clonable = False
+
+    if not clonable:
+        sys.exit(1)
+
+
+def run_checks(file_to_check):
+    data = parse_yaml_file(file_to_check)
+    validate_data_by_schema(data, file_to_check)
+    check_duplicate_projects(data)
+    check_alphabetical_order(data)
+    check_acls_config_path(data)
+    #check_upstream_clonable(data)
+
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2:
+        sys.stderr.write("Usage: {0} path/to/projects.yaml"
+                         "\n".format(sys.argv[0]))
+        sys.exit(1)
+    run_checks(sys.argv[1])
diff --git a/tests/update b/tests/update
new file mode 100755
index 0000000..1de585b
--- /dev/null
+++ b/tests/update
@@ -0,0 +1,38 @@
+#!/bin/bash -ex
+: ${JEEPYB_WORKSPACE:=$(pwd)/.workspace}
+
+PROJECTS_INI=${JEEPYB_WORKSPACE}/projects.ini
+PROJECTS_YAML=$(pwd)/projects.yaml
+
+export PROJECTS_INI PROJECTS_YAML
+
+mkdir -p "${JEEPYB_WORKSPACE}"
+
+cp "$(pwd)/conf/projects.ini.template" "${PROJECTS_INI}"
+
+[ -n "${JEEPYB_GERRIT_HOST}" ] \
+    && sed -i "s|^gerrit-host.*|gerrit-host=${JEEPYB_GERRIT_HOST}|" "${PROJECTS_INI}"
+[ -n "${JEEPYB_USER}" ] \
+    && sed -i "s|^gerrit-user.*|gerrit-user=${JEEPYB_USER}|" "${PROJECTS_INI}"
+[ -n "${JEEPYB_COMMITTER}" ] \
+    && sed -i "s|^gerrit-committer.*|gerrit-committer=${JEEPYB_COMMITTER}|" "${PROJECTS_INI}"
+[ -n "${JEEPYB_SSH_KEY}" ] \
+    && echo "gerrit-key=${JEEPYB_SSH_KEY}" >> "${PROJECTS_INI}"
+
+COMMITTER=$(git config --file "${PROJECTS_INI}" projects.gerrit-committer)
+GIT_COMMITTER_NAME=$(echo "${COMMITTER}" | awk -F '[<>]' '{print $1}')
+GIT_COMMITTER_NAME=${GIT_COMMITTER_NAME% *}
+GIT_COMMITTER_EMAIL=$(echo "${COMMITTER}" | awk -F '[<>]' '{print $2}')
+export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
+
+sed -i "s|^gerrit-system-user.*|gerrit-system-user=$(id -u)|" "${PROJECTS_INI}"
+sed -i "s|^gerrit-system-group.*|gerrit-system-group=$(id -u)|" "${PROJECTS_INI}"
+sed -i "s|^acl-dir.*|acl-dir=$(pwd)/acls|" "${PROJECTS_INI}"
+sed -i "s|^local-git-dir.*|local-git-dir=${JEEPYB_WORKSPACE}/git|" "${PROJECTS_INI}"
+sed -i "s|^jeepyb-cache-dir.*|jeepyb-cache-dir=${JEEPYB_WORKSPACE}/cache|" "${PROJECTS_INI}"
+
+# Backward compatibility with legacy format:
+# remove acls/ path prefix from `acl-config` params
+sed -i 's|acl-config: acls/|acl-config: |g' "${PROJECTS_YAML}"
+
+manage-projects -v -d $@