Initial implementation of 'readonly' plugin

The initial implementation is based on the 'readonly' groovy script
from the 'scripts' project. The advantage of splitting it out to a
standalone full plugin is that it is not necessary for the groovy
scripting plugin to also be installed on the server.

The functionality implemented in the initial version is the same as
in the groovy script, and also has the same limitations. That is, it
can only prevent changes from being made to repositories by git push.
It does not make Gerrit truly read-only because is still possible to
cause server-side changes to be made in various other ways:

- Creating a new project
- Changing a project configuration (without review)
- Any PUT/POST/DELETE request via the REST API
- Adding review comments via SSH command
- and possibly others

Prevention of these operations should be implemented in follow-up
commits.

Change-Id: If9a5ec53ec9d33001fa8fd32c895f1448dc26347
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a6ef824
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/bazel-*
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..cf9a4be
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,11 @@
+load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+
+gerrit_plugin(
+    name = "readonly",
+    srcs = glob(["src/main/java/**/*.java"]),
+    manifest_entries = [
+        "Gerrit-PluginName: readonly",
+        "Gerrit-Module: com.googlesource.gerrit.plugins.readonly.Module",
+    ],
+    resources = glob(["src/main/**/*"]),
+)
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..77bf2b2
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,26 @@
+workspace(name = "readonly")
+
+load("//:bazlets.bzl", "load_bazlets")
+
+load_bazlets(
+    commit = "21e71dc9abb42f5ac80c51d2df2a374c3414b9d2",
+    #    local_path = "/home/<user>/projects/bazlets",
+)
+
+# Release Plugin API
+load(
+    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+    "gerrit_api",
+)
+
+# Snapshot Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+#    "gerrit_api_maven_local",
+#)
+
+# Load release Plugin API
+gerrit_api()
+
+# Load snapshot Plugin API
+#gerrit_api_maven_local()
diff --git a/bazlets.bzl b/bazlets.bzl
new file mode 100644
index 0000000..e14e488
--- /dev/null
+++ b/bazlets.bzl
@@ -0,0 +1,17 @@
+NAME = "com_googlesource_gerrit_bazlets"
+
+def load_bazlets(
+    commit,
+    local_path = None
+  ):
+  if not local_path:
+      native.git_repository(
+          name = NAME,
+          remote = "https://gerrit.googlesource.com/bazlets",
+          commit = commit,
+      )
+  else:
+      native.local_repository(
+          name = NAME,
+          path = local_path,
+      )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/readonly/Module.java b/src/main/java/com/googlesource/gerrit/plugins/readonly/Module.java
new file mode 100644
index 0000000..88f681a
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/readonly/Module.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.readonly;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.server.git.validators.CommitValidationListener;
+import com.google.inject.AbstractModule;
+
+class Module extends AbstractModule {
+  @Override
+  protected void configure() {
+    DynamicSet.bind(binder(), CommitValidationListener.class).to(ReadOnly.class);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnly.java b/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnly.java
new file mode 100644
index 0000000..d933e78
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/readonly/ReadOnly.java
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.readonly;
+
+import com.google.gerrit.server.events.CommitReceivedEvent;
+import com.google.gerrit.server.git.validators.CommitValidationException;
+import com.google.gerrit.server.git.validators.CommitValidationListener;
+import com.google.gerrit.server.git.validators.CommitValidationMessage;
+import com.google.inject.Singleton;
+import java.util.List;
+
+@Singleton
+class ReadOnly implements CommitValidationListener {
+  private static final String READ_ONLY_MSG = "Gerrit is under maintenance - all data is READ ONLY";
+
+  @Override
+  public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent)
+      throws CommitValidationException {
+    throw new CommitValidationException(READ_ONLY_MSG);
+  }
+}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
new file mode 100644
index 0000000..6cfc10a
--- /dev/null
+++ b/src/main/resources/Documentation/about.md
@@ -0,0 +1 @@
+A plugin to make Gerrit run in read-only mode.
diff --git a/tools/bazel.rc b/tools/bazel.rc
new file mode 100644
index 0000000..4ed16cf
--- /dev/null
+++ b/tools/bazel.rc
@@ -0,0 +1,2 @@
+build --workspace_status_command=./tools/workspace-status.sh
+test --build_tests_only
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/bzl/BUILD
diff --git a/tools/bzl/classpath.bzl b/tools/bzl/classpath.bzl
new file mode 100644
index 0000000..dfcbe9c
--- /dev/null
+++ b/tools/bzl/classpath.bzl
@@ -0,0 +1,2 @@
+load("@com_googlesource_gerrit_bazlets//tools:classpath.bzl",
+     "classpath_collector")
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
new file mode 100644
index 0000000..956dd59
--- /dev/null
+++ b/tools/bzl/plugin.bzl
@@ -0,0 +1,5 @@
+load(
+    "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
+    "gerrit_plugin",
+    "PLUGIN_DEPS",
+)
diff --git a/tools/workspace-status.sh b/tools/workspace-status.sh
new file mode 100755
index 0000000..359d1b9
--- /dev/null
+++ b/tools/workspace-status.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# This script will be run by bazel when the build process starts to
+# generate key-value information that represents the status of the
+# workspace. The output should be like
+#
+# KEY1 VALUE1
+# KEY2 VALUE2
+#
+# If the script exits with non-zero code, it's considered as a failure
+# and the output will be discarded.
+
+function rev() {
+  cd $1; git describe --always --match "v[0-9].*" --dirty
+}
+
+echo STABLE_BUILD_READONLY_LABEL $(rev .)