Copyright plugin source.
Touched all the source for the copyright plugin for gerrit team review.
Omitted .../testdata/archives/ which contains binary archives
containing files from .../testdata/licenses/
Change-Id: Ifdc8aae584598ad4ce1f8c8372468b51fb593a4d
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/CheckConfig.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/CheckConfig.java
index d9dd534..14c4e7f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/CheckConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/CheckConfig.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -18,6 +18,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
@@ -37,6 +38,7 @@
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -57,10 +59,11 @@
private static final String LABEL = "label";
private static final String PLUGIN = "plugin";
private static final int BUFFER_SIZE = 2048;
- private static final char[] BUFFER = new char[BUFFER_SIZE];
private String pluginName;
+ /** All-Projects project.config contents. */
private Config configProject;
+ /** Plugin config from All-Projects project.config file. */
ScannerConfig scannerConfig;
public CheckConfig(String pluginName, String projectConfigContents)
@@ -82,27 +85,6 @@
this.scannerConfig.readConfigFile(pluginConfig);
}
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (other == null) {
- return false;
- }
- if (other instanceof CheckConfig) {
- CheckConfig that = (CheckConfig) other;
- return Objects.equals(this.pluginName, that.pluginName)
- && Objects.equals(this.scannerConfig, that.scannerConfig);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(pluginName, scannerConfig);
- }
-
/**
* Validates the final state of {@code trialConfig}.
*
@@ -111,6 +93,9 @@
*/
public static void checkProjectConfig(
CopyrightReviewApi reviewApi, boolean pluginEnabled, CheckConfig trialConfig) {
+ // Warn without blocking project.config pushes when plugin disabled across entire server.
+ ValidationMessage.Type errorWhenActive =
+ pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING;
CurrentUser fromUser =
reviewApi == null
? null
@@ -127,7 +112,7 @@
? "the plugin"
: fromUser.getLoggableName())
+ " will vote on"),
- pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING));
+ errorWhenActive));
} else {
String labelName = trialConfig.scannerConfig.reviewLabel.trim();
if (!trialConfig.configProject.getSubsections(LABEL).contains(labelName)) {
@@ -137,8 +122,10 @@
ScannerConfig.KEY_REVIEW_LABEL,
labelName,
"no [" + LABEL + " \"" + labelName + "\"] section configured."),
- pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING));
+ errorWhenActive));
}
+
+ // Enforce at least 1 approver exists for the copyright review label for content changes.
String[] voters =
trialConfig.configProject.getStringList(
ACCESS, RefNames.REFS_HEADS + "*", "label-" + labelName);
@@ -160,8 +147,10 @@
+ " on "
+ RefNames.REFS_HEADS
+ "*"),
- pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING));
+ errorWhenActive));
}
+
+ // Enforce an approver exists for the copyright review label for configuration changes.
voters =
trialConfig.configProject.getStringList(
ACCESS, RefNames.REFS_CONFIG, "label-" + labelName);
@@ -179,7 +168,7 @@
ScannerConfig.KEY_REVIEW_LABEL,
labelName,
"no configured approvers for " + labelName + " on " + RefNames.REFS_CONFIG),
- pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING));
+ errorWhenActive));
}
}
if (trialConfig.scannerConfig.reviewers.isEmpty()) {
@@ -199,7 +188,7 @@
+ " non-interactive user with full voting permissions for the review label '"
+ trialConfig.scannerConfig.reviewLabel
+ "'"),
- pluginEnabled ? ValidationMessage.Type.ERROR : ValidationMessage.Type.WARNING));
+ errorWhenActive));
// TODO: inject ReviewerAdder into reviewApi, and use ReviewerAdder.prepare
// a la
// https://gerrit.googlesource.com/gerrit/+/refs/heads/master/java/com/google/gerrit/server/restapi/change/PostReview.java#265
@@ -252,7 +241,7 @@
* the output on success into the commit message.
*
* <p>This method scans the commit message to find the copied text. If the text was created for
- * the same pattern signagure, this method returns a single valid finding with the number of
+ * the same pattern signature, this method returns a single valid finding with the number of
* microseconds it took to scan a large file, which can be used to block patterns that cause
* excessive backtracking.
*
@@ -289,7 +278,6 @@
new CopyrightReviewApi.CommitMessageFinding(
commitMessage, m.group(), m.group(1), m.start(), m.end()));
}
- logger.atSevere().log("signature for %s is %s", m.group(1), signature);
builder.add(
new CopyrightReviewApi.CommitMessageFinding(
commitMessage, m.group(), m.start(), m.end()));
@@ -329,15 +317,14 @@
/** Checks whether {@code trialConfig} might cause excessive backtracking. */
private long timeLargeFileInMicros() throws IOException {
- long startNanos = System.nanoTime();
+ Stopwatch sw = Stopwatch.createStarted();
try {
IndexedLineReader file = largeFile();
scannerConfig.scanner.findMatches("file", -1, file);
} finally {
- long elapsedNanos = System.nanoTime() - startNanos;
- long elapsedMicros = elapsedNanos / 1000;
- logger.atFine().log("timeLargeFile %dms", elapsedMicros / 1000);
- return elapsedMicros;
+ sw.stop();
+ logger.atFine().log("timeLargeFile %dms", sw.elapsed(TimeUnit.MILLISECONDS));
+ return sw.elapsed(TimeUnit.MICROSECONDS);
}
}
@@ -436,7 +423,7 @@
/** Read the contents of a project.config file from {@code ilr}. */
private static String readProjectConfigFile(IndexedLineReader ilr) throws IOException {
StringBuilder sb = new StringBuilder();
- CharBuffer cb = CharBuffer.wrap(BUFFER);
+ CharBuffer cb = CharBuffer.wrap(new char[BUFFER_SIZE]);
while (ilr.read(cb) >= 0) {
cb.flip();
sb.append(cb);
@@ -459,6 +446,7 @@
return Hashing.farmHashFingerprint64().hashBytes(sb.toString().getBytes(UTF_8)).toString();
}
+ // TODO: move check from command-line tool to background thread with timeout.
/** Entry point for command-line tool to check for excessive backtracking. */
public static void main(String[] args) {
if (args.length != 2) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfig.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfig.java
index 5c30033..af45703 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfig.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -16,20 +16,18 @@
import static java.nio.charset.StandardCharsets.UTF_8;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.changes.AddReviewerResult;
import com.google.gerrit.extensions.api.changes.ReviewResult;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.events.RevisionCreatedListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.Description.Units;
-import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
@@ -51,7 +49,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Constants;
@@ -65,9 +62,13 @@
/** Listener to manage configuration for enforcing review of copyright declarations and licenses. */
@Singleton
class CopyrightConfig
- implements CommitValidationListener, RevisionCreatedListener, GitReferenceUpdatedListener {
+ implements CommitValidationListener,
+ RevisionCreatedListener,
+ GitReferenceUpdatedListener,
+ LifecycleListener {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ /** Default value of timeTestMax configuration parameter for avoiding excessive backtracking. */
private final long DEFAULT_MAX_ELAPSED_SECONDS = 8;
private final Metrics metrics;
@@ -78,49 +79,21 @@
private final PluginConfigFactory pluginConfigFactory;
private final CopyrightReviewApi reviewApi;
- private PluginConfig gerritConfig;
- private CheckConfig checkConfig;
+ @Nullable private PluginConfig gerritConfig;
+ @Nullable private CheckConfig checkConfig;
static AbstractModule module() {
return new AbstractModule() {
@Override
protected void configure() {
DynamicSet.bind(binder(), CommitValidationListener.class).to(CopyrightConfig.class);
+ DynamicSet.bind(binder(), LifecycleListener.class).to(CopyrightConfig.class);
DynamicSet.bind(binder(), RevisionCreatedListener.class).to(CopyrightConfig.class);
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(CopyrightConfig.class);
}
};
}
- @Singleton
- private static class Metrics {
- final Timer0 readConfigTimer;
- final Timer0 checkConfigTimer;
- final Timer0 testConfigTimer;
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- readConfigTimer =
- metricMaker.newTimer(
- "read_config_latency",
- new Description("Time spent reading and parsing plugin configurations")
- .setCumulative()
- .setUnit(Units.MICROSECONDS));
- checkConfigTimer =
- metricMaker.newTimer(
- "check_config_latency",
- new Description("Time spent testing proposed plugin configurations")
- .setCumulative()
- .setUnit(Units.MICROSECONDS));
- testConfigTimer =
- metricMaker.newTimer(
- "test_config_latency",
- new Description("Time spent testing configurations against difficult file pattern")
- .setCumulative()
- .setUnit(Units.MICROSECONDS));
- }
- }
-
@Inject
CopyrightConfig(
Metrics metrics,
@@ -129,8 +102,7 @@
GitRepositoryManager repoManager,
ProjectCache projectCache,
PluginConfigFactory pluginConfigFactory,
- CopyrightReviewApi reviewApi)
- throws IOException, ConfigInvalidException {
+ CopyrightReviewApi reviewApi) {
this.metrics = metrics;
this.allProjectsName = allProjectsName;
this.pluginName = pluginName;
@@ -138,40 +110,28 @@
this.projectCache = projectCache;
this.pluginConfigFactory = pluginConfigFactory;
this.reviewApi = reviewApi;
-
- long nanoStart = System.nanoTime();
- try {
- checkConfig = readConfig(projectCache.getAllProjects().getProject().getConfigRefState());
- } finally {
- long elapsedMicros = (System.nanoTime() - nanoStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- }
- }
-
- private CopyrightConfig(
- MetricMaker metricMaker, CopyrightReviewApi reviewApi, String projectConfigContents)
- throws ConfigInvalidException {
- metrics = new Metrics(metricMaker);
- allProjectsName = new AllProjectsName("All-Projects");
- pluginName = "copyright";
- repoManager = null;
- projectCache = null;
- pluginConfigFactory = null;
- this.reviewApi = reviewApi;
- checkConfig = new CheckConfig(pluginName, projectConfigContents);
- }
-
- @VisibleForTesting
- static CopyrightConfig createTestInstance(
- MetricMaker metricMaker, CopyrightReviewApi reviewApi, String projectConfigContents)
- throws ConfigInvalidException {
- return new CopyrightConfig(metricMaker, reviewApi, projectConfigContents);
+ this.checkConfig = null;
}
ScannerConfig getScannerConfig() {
- return checkConfig.scannerConfig;
+ return checkConfig == null ? null : checkConfig.scannerConfig;
}
+ @Override
+ public void start() {
+ try (Timer0.Context ctx = metrics.readConfigTimer.start()) {
+ checkConfig = readConfig(projectCache.getAllProjects().getProject().getConfigRefState());
+ } catch (IOException | ConfigInvalidException e) {
+ logger.atSevere().withCause(e).log("unable to load configuration");
+ metrics.configurationErrors.increment(allProjectsName.get());
+ metrics.errors.increment();
+ return;
+ }
+ }
+
+ @Override
+ public void stop() {}
+
/** Listens for merges to /refs/meta/config on All-Projects to reload plugin configuration. */
@Override
public void onGitReferenceUpdated(GitReferenceUpdatedListener.Event event) {
@@ -181,17 +141,13 @@
if (!event.getProjectName().equals(allProjectsName.get())) {
return;
}
- long nanoStart = System.nanoTime();
- try {
- clearConfig();
+ try (Timer0.Context ctx = metrics.readConfigTimer.start()) {
checkConfig = readConfig(event.getNewObjectId());
} catch (IOException | ConfigInvalidException e) {
- logger.atSevere().withCause(e).log("%s plugin unable to load configuration", pluginName);
- checkConfig = null;
+ logger.atSevere().withCause(e).log("unable to load configuration");
+ metrics.configurationErrors.increment(allProjectsName.get());
+ metrics.errors.increment();
return;
- } finally {
- long elapsedMicros = (System.nanoTime() - nanoStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
}
}
@@ -205,67 +161,56 @@
if (!event.getProjectNameKey().equals(allProjectsName)) {
return Collections.emptyList();
}
- long readStart = System.nanoTime();
- long checkStart = -1;
- long elapsedMicros = -1;
CheckConfig trialConfig = null;
try {
- trialConfig = readConfig(event.commit.getName());
- elapsedMicros = (System.nanoTime() - readStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- if (Objects.equals(trialConfig.scannerConfig, checkConfig.scannerConfig)) {
+ try (Timer0.Context ctx = metrics.readConfigTimer.start()) {
+ trialConfig = readConfig(event.commit.getName());
+ }
+ if (Objects.equals(
+ trialConfig.scannerConfig, checkConfig == null ? null : checkConfig.scannerConfig)) {
return Collections.emptyList();
}
- checkStart = System.nanoTime();
- long maxElapsedSeconds =
- gerritConfig == null
- ? DEFAULT_MAX_ELAPSED_SECONDS
- : gerritConfig.getLong(ScannerConfig.KEY_TIME_TEST_MAX, DEFAULT_MAX_ELAPSED_SECONDS);
- if (maxElapsedSeconds > 0
- && CheckConfig.hasScanner(trialConfig)
- && !CheckConfig.scannersEqual(trialConfig, checkConfig)) {
- String commitMessage = event.commit.getFullMessage();
- ImmutableList<CopyrightReviewApi.CommitMessageFinding> findings =
- trialConfig.checkCommitMessage(commitMessage);
- if (CheckConfig.mustReportFindings(findings, maxElapsedSeconds)) {
- throw reviewApi.getCommitMessageException(pluginName, findings, maxElapsedSeconds);
+ try (Timer0.Context ctx = metrics.checkConfigTimer.start()) {
+ long maxElapsedSeconds =
+ gerritConfig == null
+ ? DEFAULT_MAX_ELAPSED_SECONDS
+ : gerritConfig.getLong(
+ ScannerConfig.KEY_TIME_TEST_MAX, DEFAULT_MAX_ELAPSED_SECONDS);
+ if (maxElapsedSeconds > 0
+ && CheckConfig.hasScanner(trialConfig)
+ && !CheckConfig.scannersEqual(trialConfig, checkConfig)) {
+ String commitMessage = event.commit.getFullMessage();
+ ImmutableList<CopyrightReviewApi.CommitMessageFinding> findings =
+ trialConfig.checkCommitMessage(commitMessage);
+ if (CheckConfig.mustReportFindings(findings, maxElapsedSeconds)) {
+ throw reviewApi.getCommitMessageException(pluginName, findings, maxElapsedSeconds);
+ }
}
+ boolean pluginEnabled =
+ gerritConfig != null && gerritConfig.getBoolean(ScannerConfig.KEY_ENABLE, false);
+ CheckConfig.checkProjectConfig(reviewApi, pluginEnabled, trialConfig);
+ List<CommitValidationMessage> messages =
+ trialConfig == null || trialConfig.scannerConfig == null
+ ? Collections.emptyList()
+ : trialConfig.scannerConfig.messages;
+ checkForConfigErrors(trialConfig);
+ return messages;
}
- boolean pluginEnabled =
- gerritConfig != null && gerritConfig.getBoolean(ScannerConfig.KEY_ENABLE, false);
- CheckConfig.checkProjectConfig(reviewApi, pluginEnabled, trialConfig);
- return trialConfig == null || trialConfig.scannerConfig == null
- ? Collections.emptyList()
- : trialConfig.scannerConfig.messages;
} catch (IOException e) {
- logger.atSevere().withCause(e).log(
- "failed to read new project.config for %s plugin", pluginName);
- throw new CommitValidationException("failed to read new project.config", e);
+ logger.atSevere().withCause(e).log("failed to read new project.config");
+ throw new CommitValidationException(
+ pluginName + "plugin failed to read new project.config", e);
} catch (ConfigInvalidException e) {
- logger.atSevere().withCause(e).log("unable to parse %s plugin config", pluginName);
+ logger.atSevere().withCause(e).log("unable to parse plugin config");
if (trialConfig != null && trialConfig.scannerConfig != null) {
trialConfig.scannerConfig.messages.add(ScannerConfig.errorMessage(e.getMessage()));
+ metrics.configurationErrors.increment(allProjectsName.get());
+ metrics.errors.increment();
+ checkForConfigErrors(trialConfig);
return trialConfig.scannerConfig.messages;
} else {
- throw new CommitValidationException("unable to parse new project.config", e);
- }
- } finally {
- if (elapsedMicros < 0) {
- elapsedMicros = (System.nanoTime() - readStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- } else if (checkStart >= 0) {
- long elapsedNanos = System.nanoTime() - checkStart;
- metrics.checkConfigTimer.record(elapsedNanos, TimeUnit.NANOSECONDS);
- }
- if (trialConfig != null
- && trialConfig.scannerConfig != null
- && trialConfig.scannerConfig.hasErrors()) {
- StringBuilder sb = new StringBuilder();
- sb.append("\nerror in ");
- sb.append(pluginName);
- sb.append(" plugin configuration");
- trialConfig.scannerConfig.appendMessages(sb);
- throw new CommitValidationException(sb.toString());
+ throw new CommitValidationException(
+ pluginName + "plugin unable to parse new project.config", e);
}
}
}
@@ -286,49 +231,49 @@
return;
}
// passed onCommitReceived so expect at worst only warnings here
- long readStart = System.nanoTime();
- long checkStart = -1;
- long elapsedMicros = -1;
CheckConfig trialConfig = null;
try {
- trialConfig = readConfig(event.getChange().currentRevision);
- elapsedMicros = (System.nanoTime() - readStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- if (Objects.equals(trialConfig, checkConfig.scannerConfig)) {
+ try (Timer0.Context ctx = metrics.readConfigTimer.start()) {
+ trialConfig = readConfig(event.getChange().currentRevision);
+ }
+ if (Objects.equals(
+ trialConfig.scannerConfig, checkConfig == null ? null : checkConfig.scannerConfig)) {
return;
}
- checkStart = System.nanoTime();
- if (CheckConfig.hasScanner(trialConfig)
- && !CheckConfig.scannersEqual(trialConfig, checkConfig)) {
- long maxElapsedSeconds =
- gerritConfig == null
- ? DEFAULT_MAX_ELAPSED_SECONDS
- : gerritConfig.getLong(
- ScannerConfig.KEY_TIME_TEST_MAX, DEFAULT_MAX_ELAPSED_SECONDS);
- if (maxElapsedSeconds > 0) {
- String commitMessage = event.getRevision().commitWithFooters;
- ImmutableList<CopyrightReviewApi.CommitMessageFinding> findings =
- trialConfig.checkCommitMessage(commitMessage);
- ReviewResult result =
- reviewApi.reportCommitMessageFindings(
- pluginName,
- allProjectsName.get(),
- checkConfig == null ? null : checkConfig.scannerConfig,
- trialConfig.scannerConfig,
- event,
- findings,
- maxElapsedSeconds);
- logReviewResultErrors(event, result);
+ try (Timer0.Context ctx = metrics.checkConfigTimer.start()) {
+ if (CheckConfig.hasScanner(trialConfig)
+ && !CheckConfig.scannersEqual(trialConfig, checkConfig)) {
+ long maxElapsedSeconds =
+ gerritConfig == null
+ ? DEFAULT_MAX_ELAPSED_SECONDS
+ : gerritConfig.getLong(
+ ScannerConfig.KEY_TIME_TEST_MAX, DEFAULT_MAX_ELAPSED_SECONDS);
+ if (maxElapsedSeconds > 0) {
+ String commitMessage = event.getRevision().commitWithFooters;
+ ImmutableList<CopyrightReviewApi.CommitMessageFinding> findings =
+ trialConfig.checkCommitMessage(commitMessage);
+ ReviewResult result =
+ reviewApi.reportCommitMessageFindings(
+ pluginName,
+ allProjectsName.get(),
+ checkConfig == null ? null : checkConfig.scannerConfig,
+ trialConfig.scannerConfig,
+ event,
+ findings,
+ maxElapsedSeconds);
+ logReviewResultErrors(event, result);
+ }
}
+ boolean pluginEnabled =
+ gerritConfig != null && gerritConfig.getBoolean(ScannerConfig.KEY_ENABLE, false);
+ CheckConfig.checkProjectConfig(reviewApi, pluginEnabled, trialConfig);
+ return;
}
- boolean pluginEnabled =
- gerritConfig != null && gerritConfig.getBoolean(ScannerConfig.KEY_ENABLE, false);
- CheckConfig.checkProjectConfig(reviewApi, pluginEnabled, trialConfig);
- return;
} catch (RestApiException | ConfigInvalidException | IOException e) {
- logger.atSevere().withCause(e).log("%s plugin unable to read new configuration", pluginName);
- // throw IllegalStateException? RestApiException?
+ logger.atSevere().withCause(e).log("unable to read new configuration");
+ metrics.configurationErrors.increment(project);
+ metrics.errors.increment();
return;
} finally {
if (trialConfig != null
@@ -341,24 +286,17 @@
pluginName,
project,
ProjectConfig.PROJECT_CONFIG,
- checkConfig.scannerConfig,
+ checkConfig == null ? null : checkConfig.scannerConfig,
trialConfig.scannerConfig,
event);
logReviewResultErrors(event, result);
} catch (RestApiException e) {
- logger.atSevere().withCause(e).log(
- "%s plugin unable to read new configuration", pluginName);
- // throw IllegalStateException? RestApiException?
+ logger.atSevere().withCause(e).log("unable to report configuration findings");
+ metrics.postReviewErrors.increment(project);
+ metrics.errors.increment();
return;
}
}
- if (elapsedMicros < 0) {
- elapsedMicros = (System.nanoTime() - readStart) / 1000;
- metrics.readConfigTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- } else if (checkStart >= 0) {
- long elapsedNanos = System.nanoTime() - checkStart;
- metrics.checkConfigTimer.record(elapsedNanos, TimeUnit.NANOSECONDS);
- }
}
}
@@ -381,18 +319,21 @@
projectState = projectCache.checkedGet(Project.nameKey(project));
} catch (IOException e) {
logger.atSevere().withCause(e).log("error getting project state of %s", project);
- // throw IllegalStateException? RestApiException?
+ metrics.projectStateErrors.increment(project);
+ metrics.errors.increment();
return scannerConfig.defaultEnable;
}
if (projectState == null) {
logger.atSevere().log("error getting project state of %s", project);
- // throw IllegalStateException? RestApiException?
+ metrics.projectStateErrors.increment(project);
+ metrics.errors.increment();
return scannerConfig.defaultEnable;
}
ProjectConfig projectConfig = projectState.getConfig();
if (projectConfig == null) {
logger.atWarning().log("error getting project config of %s", project);
- // throw IllegalStateException? RestApiException? return?
+ metrics.projectConfigErrors.increment(project);
+ metrics.errors.increment();
return scannerConfig.defaultEnable;
}
PluginConfig pluginConfig = projectConfig.getPluginConfig(pluginName);
@@ -403,6 +344,19 @@
return pluginConfig.getBoolean(ScannerConfig.KEY_ENABLE, scannerConfig.defaultEnable);
}
+ private void checkForConfigErrors(CheckConfig trialConfig) throws CommitValidationException {
+ if (trialConfig != null
+ && trialConfig.scannerConfig != null
+ && trialConfig.scannerConfig.hasErrors()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\nerror in ");
+ sb.append(pluginName);
+ sb.append(" plugin configuration");
+ trialConfig.scannerConfig.appendMessages(sb);
+ throw new CommitValidationException(sb.toString());
+ }
+ }
+
/**
* Loads and compiles configured patterns from {@code ref/meta/All-Projects/project.config} and
* {@code gerrit.config}.
@@ -411,6 +365,7 @@
* @return the new scanner configuration to check
* @throws IOException if accessing the repository fails
*/
+ @Nullable
private CheckConfig readConfig(String projectConfigObjectId)
throws IOException, ConfigInvalidException {
CheckConfig checkConfig = null;
@@ -425,7 +380,6 @@
}
gerritConfig = pluginConfigFactory.getFromGerritConfig(pluginName, true);
if (gerritConfig == null) {
- // throw IllegalStateException? RestApiException?
checkConfig.scannerConfig.messages.add(
ScannerConfig.hintMessage(
"missing [plugin \"" + pluginName + "\"] section in gerrit.config"));
@@ -436,32 +390,31 @@
return checkConfig;
}
- /** Erases any prior configuration state. */
- private void clearConfig() {
- checkConfig = null;
- }
-
private void logReviewResultErrors(RevisionCreatedListener.Event event, ReviewResult result) {
if (!Strings.isNullOrEmpty(result.error)) {
logger.atSevere().log(
- "%s plugin revision %s: error posting review: %s",
- pluginName, event.getChange().currentRevision, result.error);
+ "revision %s: error posting review: %s", event.getChange().currentRevision, result.error);
+ metrics.postReviewErrors.increment(event.getChange().project);
+ metrics.errors.increment();
}
- for (Map.Entry<String, AddReviewerResult> entry : result.reviewers.entrySet()) {
- AddReviewerResult arr = entry.getValue();
- if (!Strings.isNullOrEmpty(arr.error)) {
- logger.atSevere().log(
- "%s plugin revision %s: error adding reviewer %s: %s",
- pluginName, event.getChange().currentRevision, entry.getKey(), arr.error);
+ if (result.reviewers != null) {
+ for (Map.Entry<String, AddReviewerResult> entry : result.reviewers.entrySet()) {
+ AddReviewerResult arr = entry.getValue();
+ if (!Strings.isNullOrEmpty(arr.error)) {
+ logger.atSevere().log(
+ "revision %s: error adding reviewer %s: %s",
+ event.getChange().currentRevision, entry.getKey(), arr.error);
+ metrics.addReviewerErrors.increment(event.getChange().project);
+ metrics.errors.increment();
+ }
}
}
}
private String readFileContents(Repository repo, ObjectId objectId, String filename)
throws IOException {
- RevWalk rw = new RevWalk(repo);
- RevTree tree = rw.parseTree(objectId);
- try (TreeWalk tw = TreeWalk.forPath(rw.getObjectReader(), filename, tree)) {
+ try (RevWalk rw = new RevWalk(repo);
+ TreeWalk tw = TreeWalk.forPath(rw.getObjectReader(), filename, rw.parseTree(objectId))) {
ObjectLoader loader = repo.open(tw.getObjectId(0), Constants.OBJ_BLOB);
return new String(loader.getCachedBytes(), UTF_8);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApi.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApi.java
index 0c41d7d..de97d60 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApi.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -24,9 +24,10 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
import com.google.gerrit.extensions.api.changes.ReviewResult;
@@ -34,31 +35,17 @@
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.events.RevisionCreatedListener;
-import com.google.gerrit.extensions.restapi.IdString;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.metrics.Counter0;
-import com.google.gerrit.metrics.Counter1;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.Description.Units;
-import com.google.gerrit.metrics.Field;
-import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.metrics.Timer1;
import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.PluginUser;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.restapi.change.ListChangeComments;
-import com.google.gerrit.server.restapi.change.PostReview;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightScanner.Match;
@@ -68,7 +55,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
@@ -82,61 +68,8 @@
private final Provider<PluginUser> pluginUserProvider;
private final Provider<CurrentUser> userProvider;
private final IdentifiedUser.GenericFactory identifiedUserFactory;
- private final ChangeNotes.Factory changeNotesFactory;
- private final ChangeResource.Factory changeResourceFactory;
- private final PatchSetUtil psUtil;
- private final PostReview postReview;
- private final ListChangeComments listChangeComments;
-
- @Singleton
- static class Metrics {
- final Counter0 reviewCount;
- final Counter0 commentCount;
- final Timer0 reviewTimer;
- final Counter1 reviewCountByProject;
- final Counter1 commentCountByProject;
- final Timer1 reviewTimerByProject;
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- Field<String> project = Field.ofString("project", "project name");
- reviewCount =
- metricMaker.newCounter(
- "review_count",
- new Description("Total number of posted reviews").setRate().setUnit("reviews"));
- commentCount =
- metricMaker.newCounter(
- "comment_count",
- new Description("Total number of posted review comments")
- .setRate()
- .setUnit("comments"));
- reviewTimer =
- metricMaker.newTimer(
- "review_latency",
- new Description("Time spent posting reviews to revisions")
- .setCumulative()
- .setUnit(Units.MICROSECONDS));
- reviewCountByProject =
- metricMaker.newCounter(
- "review_count_by_project",
- new Description("Total number of posted reviews").setRate().setUnit("reviews"),
- project);
- commentCountByProject =
- metricMaker.newCounter(
- "comment_count_by_project",
- new Description("Total number of posted review comments")
- .setRate()
- .setUnit("comments"),
- project);
- reviewTimerByProject =
- metricMaker.newTimer(
- "review_latency_by_project",
- new Description("Time spent posting reviews to revisions")
- .setCumulative()
- .setUnit(Units.MICROSECONDS),
- project);
- }
- }
+ private final ThreadLocalRequestContext requestContext;
+ private final GerritApi gApi;
@Inject
CopyrightReviewApi(
@@ -144,20 +77,14 @@
Provider<PluginUser> pluginUserProvider,
Provider<CurrentUser> userProvider,
IdentifiedUser.GenericFactory identifiedUserFactory,
- ChangeNotes.Factory changeNotesFactory,
- ChangeResource.Factory changeResourceFactory,
- PatchSetUtil psUtil,
- PostReview postReview,
- ListChangeComments listChangeComments) {
+ ThreadLocalRequestContext requestContext,
+ GerritApi gApi) {
this.metrics = metrics;
this.pluginUserProvider = pluginUserProvider;
this.userProvider = userProvider;
this.identifiedUserFactory = identifiedUserFactory;
- this.changeNotesFactory = changeNotesFactory;
- this.changeResourceFactory = changeResourceFactory;
- this.psUtil = psUtil;
- this.postReview = postReview;
- this.listChangeComments = listChangeComments;
+ this.requestContext = requestContext;
+ this.gApi = gApi;
}
/**
@@ -199,7 +126,6 @@
Preconditions.checkArgument(findings.size() != 1 || !findings.get(0).isValid());
Preconditions.checkArgument(maxElapsedSeconds > 0);
- long startNanos = System.nanoTime();
metrics.reviewCount.increment();
metrics.reviewCountByProject.increment(project);
@@ -207,41 +133,43 @@
oldConfig != null && oldConfig.fromAccountId > 0
? oldConfig.fromAccountId
: newConfig.fromAccountId;
- ChangeResource change = getChange(event, fromAccountId);
- Map<String, List<CommentInfo>> priorReviewComments = getComments(change);
- if (priorReviewComments == null) {
- priorReviewComments = ImmutableMap.of();
- }
- HashSet<CommentInfo> priorComments = new HashSet<>();
- priorComments.addAll(priorReviewComments.get("/COMMIT_MSG"));
-
- ReviewInput ri = new ReviewInput();
- ri.message(getCommitMessageMessage(pluginName, findings, maxElapsedSeconds));
- ImmutableList<CommentInput> comments =
- ImmutableList.copyOf(
- getCommitMessageComments(pluginName, findings, maxElapsedSeconds).stream()
- .filter(ci -> !priorComments.contains(ci))
- .toArray(i -> new CommentInput[i]));
- if (!comments.isEmpty()) {
- ri.comments = ImmutableMap.of("/COMMIT_MSG", comments);
- }
- String label = "Code-Review";
- if (!Strings.isNullOrEmpty(oldConfig.reviewLabel)) {
- label = oldConfig.reviewLabel;
- } else if (!Strings.isNullOrEmpty(newConfig.reviewLabel)) {
- label = newConfig.reviewLabel;
- }
- int vote = (findings.size() != 1 || !findings.get(0).isValid()) ? -2 : 2;
- if (vote == 2) {
- long elapsedMicros = findings.get(0).elapsedMicros;
- if (elapsedMicros > maxElapsedSeconds * 1000000) {
- vote = -2;
- } else if (elapsedMicros > 2000000) {
- vote = 1;
+ try (ManualRequestContext ctx = getContext(fromAccountId)) {
+ ChangeApi cApi = gApi.changes().id(event.getChange().id);
+ Map<String, List<CommentInfo>> priorReviewComments = cApi.comments();
+ if (priorReviewComments == null) {
+ priorReviewComments = ImmutableMap.of();
}
+ HashSet<CommentInfo> priorComments = new HashSet<>();
+ priorComments.addAll(priorReviewComments.get("/COMMIT_MSG"));
+
+ ReviewInput ri = new ReviewInput();
+ ri.message(getCommitMessageMessage(pluginName, findings, maxElapsedSeconds));
+ ImmutableList<CommentInput> comments =
+ ImmutableList.copyOf(
+ getCommitMessageComments(pluginName, findings, maxElapsedSeconds).stream()
+ .filter(ci -> !priorComments.contains(ci))
+ .toArray(i -> new CommentInput[i]));
+ if (!comments.isEmpty()) {
+ ri.comments = ImmutableMap.of("/COMMIT_MSG", comments);
+ }
+ String label = "Code-Review";
+ if (!Strings.isNullOrEmpty(oldConfig.reviewLabel)) {
+ label = oldConfig.reviewLabel;
+ } else if (!Strings.isNullOrEmpty(newConfig.reviewLabel)) {
+ label = newConfig.reviewLabel;
+ }
+ int vote = (findings.size() != 1 || !findings.get(0).isValid()) ? -2 : 2;
+ if (vote == 2) {
+ long elapsedMicros = findings.get(0).elapsedMicros;
+ if (elapsedMicros > maxElapsedSeconds * 1000000) {
+ vote = -2;
+ } else if (elapsedMicros > 2000000) {
+ vote = 1;
+ }
+ }
+ ri.label(label, vote);
+ return cApi.current().review(ri);
}
- ri.label(label, vote);
- return review(change, ri);
}
/**
@@ -308,22 +236,23 @@
Preconditions.checkNotNull(newConfig.messages);
Preconditions.checkArgument(!newConfig.messages.isEmpty());
- long startNanos = System.nanoTime();
metrics.reviewCount.increment();
metrics.reviewCountByProject.increment(project);
- try {
- int fromAccountId =
- oldConfig != null && oldConfig.fromAccountId > 0
- ? oldConfig.fromAccountId
- : newConfig.fromAccountId;
- ChangeResource change = getChange(event, fromAccountId);
+ int fromAccountId =
+ oldConfig != null && oldConfig.fromAccountId > 0
+ ? oldConfig.fromAccountId
+ : newConfig.fromAccountId;
+ try (Timer0.Context t0 = metrics.reviewTimer.start();
+ Timer1.Context t1 = metrics.reviewTimerByProject.start(project);
+ ManualRequestContext ctx = getContext(fromAccountId)) {
+ ChangeApi cApi = gApi.changes().id(event.getChange().id);
StringBuilder message = new StringBuilder();
message.append(pluginName);
message.append(" plugin issues parsing new configuration");
ReviewInput ri = new ReviewInput().message(message.toString());
- Map<String, List<CommentInfo>> priorComments = getComments(change);
+ Map<String, List<CommentInfo>> priorComments = cApi.comments();
if (priorComments == null) {
priorComments = ImmutableMap.of();
}
@@ -350,11 +279,7 @@
}
metrics.commentCount.incrementBy((long) numComments);
metrics.commentCountByProject.incrementBy(project, (long) numComments);
- return review(change, ri);
- } finally {
- long elapsedMicros = (System.nanoTime() - startNanos) / 1000;
- metrics.reviewTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- metrics.reviewTimerByProject.record(project, elapsedMicros, TimeUnit.MICROSECONDS);
+ return cApi.current().review(ri);
}
}
@@ -373,11 +298,12 @@
RevisionCreatedListener.Event event,
Map<String, ImmutableList<Match>> findings)
throws RestApiException {
- long startNanos = System.nanoTime();
metrics.reviewCount.increment();
metrics.reviewCountByProject.increment(project);
- try {
+ try (Timer0.Context t0 = metrics.reviewTimer.start();
+ Timer1.Context t1 = metrics.reviewTimerByProject.start(project);
+ ManualRequestContext ctx = getContext(scannerConfig.fromAccountId)) {
boolean tpAllowed = scannerConfig.isThirdPartyAllowed(project);
boolean reviewRequired = false;
for (Map.Entry<String, ImmutableList<Match>> entry : findings.entrySet()) {
@@ -395,7 +321,7 @@
break;
}
}
- ChangeResource change = getChange(event, scannerConfig.fromAccountId);
+ ChangeApi cApi = gApi.changes().id(event.getChange().id);
ReviewInput ri =
new ReviewInput()
.message("Copyright scan")
@@ -411,7 +337,7 @@
} else {
ri = ri.message("This change appears to comply with copyright requirements.");
}
- Map<String, List<CommentInfo>> priorComments = getComments(change);
+ Map<String, List<CommentInfo>> priorComments = cApi.comments();
if (priorComments == null) {
priorComments = ImmutableMap.of();
}
@@ -450,11 +376,7 @@
}
metrics.commentCount.incrementBy((long) numCommentsAdded);
metrics.commentCountByProject.incrementBy(project, (long) numCommentsAdded);
- return review(change, ri);
- } finally {
- long elapsedMicros = (System.nanoTime() - startNanos) / 1000;
- metrics.reviewTimer.record(elapsedMicros, TimeUnit.MICROSECONDS);
- metrics.reviewTimerByProject.record(project, elapsedMicros, TimeUnit.MICROSECONDS);
+ return cApi.current().review(ri);
}
}
@@ -631,26 +553,13 @@
return sb.toString();
}
- /**
- * Constructs a {@link com.google.gerrit.server.change.ChangeResource} from the notes log for the
- * change onto which a new revision was pushed.
- *
- * @param event describes the newly pushed revision
- * @param fromAccountId identifies the configured user to impersonate when sending review comments
- * @throws RestApiException if an error occurs looking up the notes log for the change
- */
- private ChangeResource getChange(RevisionCreatedListener.Event event, int fromAccountId)
- throws RestApiException {
- try {
- CurrentUser fromUser = getSendingUser(fromAccountId);
- ChangeNotes notes = changeNotesFactory.createChecked(Change.id(event.getChange()._number));
- return changeResourceFactory.create(notes, fromUser);
- } catch (Exception e) {
- Throwables.throwIfUnchecked(e);
- throw e instanceof RestApiException
- ? (RestApiException) e
- : new RestApiException("Cannot load change", e);
- }
+ private ManualRequestContext getContext(int fromAccountId) {
+ PluginUser pluginUser = pluginUserProvider.get();
+ CurrentUser user =
+ fromAccountId <= 0
+ ? userProvider.get()
+ : identifiedUserFactory.runAs(null, Account.id(fromAccountId), pluginUser);
+ return new ManualRequestContext(user, requestContext);
}
/**
@@ -665,44 +574,6 @@
return ri;
}
- /**
- * Retrieves all of the prior review comments already attached to {@code change}.
- *
- * @throws RestApiException if an error occurs retrieving the comments
- */
- private Map<String, List<CommentInfo>> getComments(ChangeResource change)
- throws RestApiException {
- try {
- return listChangeComments.apply(change);
- } catch (Exception e) {
- Throwables.throwIfUnchecked(e);
- throw e instanceof RestApiException
- ? (RestApiException) e
- : new RestApiException("Cannot list comments", e);
- }
- }
-
- /**
- * Adds the code review described by {@code ri} to the review thread of {@code change}.
- *
- * @throws RestApiException if an error occurs updating the review thread
- */
- private ReviewResult review(ChangeResource change, ReviewInput ri) throws RestApiException {
- try {
- PatchSet ps = psUtil.current(change.getNotes());
- if (ps == null) {
- throw new ResourceNotFoundException(IdString.fromDecoded("current"));
- }
- RevisionResource revision = RevisionResource.createNonCacheable(change, ps);
- return postReview.apply(revision, ri).value();
- } catch (Exception e) {
- Throwables.throwIfUnchecked(e);
- throw e instanceof RestApiException
- ? (RestApiException) e
- : new RestApiException("Cannot post review", e);
- }
- }
-
/** Returns true if {@code priorComments} already includes a comment identical to {@code ci}. */
@VisibleForTesting
boolean containsComment(Iterable<? extends Comment> priorComments, CommentInput ci) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidator.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidator.java
index 0a77834..7ed50dd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidator.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -26,12 +26,6 @@
import com.google.gerrit.extensions.events.RevisionCreatedListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.metrics.Counter0;
-import com.google.gerrit.metrics.Counter1;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.Description.Units;
-import com.google.gerrit.metrics.Field;
-import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.metrics.Timer1;
import com.google.gerrit.reviewdb.client.Project;
@@ -40,14 +34,12 @@
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.AbstractModule;
-import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightScanner.Match;
import com.googlesource.gerrit.plugins.copyright.lib.IndexedLineReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
@@ -81,79 +73,6 @@
};
}
- @Singleton
- private static class Metrics {
- final Counter0 scanCount;
- final Timer0 scanRevisionTimer;
- final Timer0 scanFileTimer;
- final Counter1 scanCountByProject;
- final Timer1 scanRevisionTimerByProject;
- final Timer1 scanFileTimerByProject;
- final Counter1 scanCountByBranch;
- final Timer1 scanRevisionTimerByBranch;
- final Timer1 scanFileTimerByBranch;
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- Field<String> project = Field.ofString("project", "project name");
- Field<String> branch = Field.ofString("branch", "branch name");
- scanCount =
- metricMaker.newCounter(
- "scan_count",
- new Description("Total number of copyright scans").setRate().setUnit("scans"));
- scanRevisionTimer =
- metricMaker.newTimer(
- "scan_revision_latency",
- new Description("Time spent scanning entire revisions")
- .setCumulative()
- .setUnit(Units.MILLISECONDS));
- scanFileTimer =
- metricMaker.newTimer(
- "scan_file_latency",
- new Description("Time spent scanning each file")
- .setCumulative()
- .setUnit(Units.MICROSECONDS));
- scanCountByProject =
- metricMaker.newCounter(
- "scan_count_by_project",
- new Description("Total number of copyright scans").setRate().setUnit("scans"),
- project);
- scanRevisionTimerByProject =
- metricMaker.newTimer(
- "scan_revision_latency_by_project",
- new Description("Time spent scanning entire revisions")
- .setCumulative()
- .setUnit(Units.MILLISECONDS),
- project);
- scanFileTimerByProject =
- metricMaker.newTimer(
- "scan_file_latency_by_project",
- new Description("Time spent scanning each file")
- .setCumulative()
- .setUnit(Units.MICROSECONDS),
- project);
- scanCountByBranch =
- metricMaker.newCounter(
- "scan_count_by_branch",
- new Description("Total number of copyright scans").setRate().setUnit("scans"),
- branch);
- scanRevisionTimerByBranch =
- metricMaker.newTimer(
- "scan_revision_latency_by_branch",
- new Description("Time spent scanning entire revisions")
- .setCumulative()
- .setUnit(Units.MILLISECONDS),
- branch);
- scanFileTimerByBranch =
- metricMaker.newTimer(
- "scan_file_latency_by_branch",
- new Description("Time spent scanning each file")
- .setCumulative()
- .setUnit(Units.MICROSECONDS),
- branch);
- }
- }
-
@Inject
CopyrightValidator(
Metrics metrics,
@@ -189,16 +108,18 @@
if (scannerConfig == null) {
// error already reported during configuration load
logger.atWarning().log(
- "%s plugin enabled with no configuration -- not scanning revision %s",
- pluginName, event.getChange().currentRevision);
+ "plugin enabled with no configuration -- not scanning revision %s",
+ event.getChange().currentRevision);
+ metrics.skippedReviewWarnings.increment(project);
return;
}
if (scannerConfig.scanner == null) {
if (scannerConfig.hasErrors()) {
// error already reported during configuration load
logger.atWarning().log(
- "%s plugin enabled with errors in configuration -- not scanning revision %s",
- pluginName, event.getChange().currentRevision);
+ "plugin enabled with errors in configuration -- not scanning revision %s",
+ event.getChange().currentRevision);
+ metrics.skippedReviewWarnings.increment(project);
} // else plugin not enabled
return;
}
@@ -210,7 +131,9 @@
scanRevision(project, branch, event);
} catch (IOException | RestApiException e) {
logger.atSevere().withCause(e).log(
- "%s plugin cannot scan revision %s", pluginName, event.getChange().currentRevision);
+ "cannot scan revision %s", event.getChange().currentRevision);
+ metrics.scanErrors.increment(project);
+ metrics.errors.increment();
return;
}
}
@@ -228,12 +151,13 @@
throws IOException, RestApiException {
Map<String, ImmutableList<Match>> findings = new HashMap<>();
ArrayList<String> containedPaths = new ArrayList<>();
- long scanStart = System.nanoTime();
- metrics.scanCount.increment();
metrics.scanCountByProject.increment(project);
metrics.scanCountByBranch.increment(branch);
- try (Repository repo = repoManager.openRepository(Project.nameKey(project));
+ try (Timer0.Context t0 = metrics.scanRevisionTimer.start();
+ Timer1.Context t1project = metrics.scanRevisionTimerByProject.start(project);
+ Timer1.Context t1branch = metrics.scanRevisionTimerByBranch.start(branch);
+ Repository repo = repoManager.openRepository(Project.nameKey(project));
RevWalk revWalk = new RevWalk(repo);
TreeWalk tw = new TreeWalk(revWalk.getObjectReader())) {
RevCommit commit = repo.parseCommit(ObjectId.fromString(event.getRevision().commit.commit));
@@ -259,8 +183,10 @@
&& !FileMode.REGULAR_FILE.equals(tw.getFileMode())) {
continue;
}
- long fileStart = System.nanoTime();
- try (ObjectReader reader = tw.getObjectReader();
+ try (Timer0.Context tf0 = metrics.scanFileTimer.start();
+ Timer1.Context tf1project = metrics.scanFileTimerByProject.start(project);
+ Timer1.Context tf1branch = metrics.scanFileTimerByBranch.start(branch);
+ ObjectReader reader = tw.getObjectReader();
ObjectStream stream = reader.open(tw.getObjectId(0)).openStream()) {
IndexedLineReader lineReader = new IndexedLineReader(fullPath, -1, stream);
ImmutableList<Match> matches =
@@ -268,31 +194,26 @@
if (!matches.isEmpty()) {
findings.put(tw.getPathString(), matches);
}
- long fileTime = (System.nanoTime() - fileStart) / 1000;
- metrics.scanFileTimer.record(fileTime, TimeUnit.MICROSECONDS);
- metrics.scanFileTimerByProject.record(project, fileTime, TimeUnit.MICROSECONDS);
- metrics.scanFileTimerByBranch.record(branch, fileTime, TimeUnit.MICROSECONDS);
}
}
}
- long scanTime = (System.nanoTime() - scanStart) / 1000000;
- metrics.scanRevisionTimer.record(scanTime, TimeUnit.MILLISECONDS);
- metrics.scanRevisionTimerByProject.record(project, scanTime, TimeUnit.MILLISECONDS);
- metrics.scanRevisionTimerByBranch.record(branch, scanTime, TimeUnit.MILLISECONDS);
ReviewResult result = reviewApi.reportScanFindings(project, scannerConfig, event, findings);
if (result != null && result.error != null && !result.error.equals("")) {
logger.atSevere().log(
- "%s plugin revision %s: error posting review: %s",
- pluginName, event.getChange().currentRevision, result.error);
+ "revision %s: error posting review: %s", event.getChange().currentRevision, result.error);
+ metrics.postReviewErrors.increment(project);
+ metrics.errors.increment();
}
if (result != null && result.reviewers != null) {
for (Map.Entry<String, AddReviewerResult> entry : result.reviewers.entrySet()) {
AddReviewerResult arr = entry.getValue();
if (arr.error != null && !arr.error.equals("")) {
logger.atSevere().log(
- "%s plugin revision %s: error adding reviewer %s: %s",
- pluginName, event.getChange().currentRevision, entry.getKey(), arr.error);
+ "revision %s: error adding reviewer %s: %s",
+ event.getChange().currentRevision, entry.getKey(), arr.error);
+ metrics.addReviewerErrors.increment(project);
+ metrics.errors.increment();
}
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/Metrics.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/Metrics.java
new file mode 100644
index 0000000..1e22006
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/Metrics.java
@@ -0,0 +1,216 @@
+// Copyright (C) 2019 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.copyright;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Description.Units;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer0;
+import com.google.gerrit.metrics.Timer1;
+import com.google.inject.Singleton;
+import javax.inject.Inject;
+
+@Singleton
+class Metrics {
+ final Timer0 readConfigTimer;
+ final Timer0 checkConfigTimer;
+ final Timer0 testConfigTimer;
+ final Counter1<String> postReviewErrors;
+ final Counter1<String> addReviewerErrors;
+ final Counter1<String> projectStateErrors;
+ final Counter1<String> projectConfigErrors;
+ final Counter1<String> configurationErrors;
+ final Counter0 reviewCount;
+ final Counter0 commentCount;
+ final Timer0 reviewTimer;
+ final Counter1<String> reviewCountByProject;
+ final Counter1<String> commentCountByProject;
+ final Timer1<String> reviewTimerByProject;
+ final Timer0 scanRevisionTimer;
+ final Timer0 scanFileTimer;
+ final Counter1<String> scanCountByProject;
+ final Timer1<String> scanRevisionTimerByProject;
+ final Timer1<String> scanFileTimerByProject;
+ final Counter1<String> scanCountByBranch;
+ final Timer1<String> scanRevisionTimerByBranch;
+ final Timer1<String> scanFileTimerByBranch;
+ final Counter1<String> skippedReviewWarnings;
+ final Counter1<String> scanErrors;
+ final Counter0 errors;
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ Field<String> project = Field.ofString("project", "project name");
+ Field<String> branch = Field.ofString("branch", "branch name");
+
+ readConfigTimer =
+ metricMaker.newTimer(
+ "read_config_latency",
+ new Description("Time spent reading and parsing plugin configurations")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS));
+ checkConfigTimer =
+ metricMaker.newTimer(
+ "check_config_latency",
+ new Description("Time spent testing proposed plugin configurations")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS));
+ testConfigTimer =
+ metricMaker.newTimer(
+ "test_config_latency",
+ new Description("Time spent testing configurations against difficult file pattern")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS));
+ postReviewErrors =
+ metricMaker.newCounter(
+ "post_review_error_count",
+ new Description("Number of failed attempts to post reviews")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ addReviewerErrors =
+ metricMaker.newCounter(
+ "add_reviewer_error_count",
+ new Description("Number of failed attempts to add a reviewer")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ projectStateErrors =
+ metricMaker.newCounter(
+ "read_project_state_error_count",
+ new Description("Number of failed attempts to read project state")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ projectConfigErrors =
+ metricMaker.newCounter(
+ "get_project_config_error_count",
+ new Description("Number of failed attempts to get config from project state")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ configurationErrors =
+ metricMaker.newCounter(
+ "read_configuration_error_count",
+ new Description("Number of failed attempts to read configuration")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ reviewCount =
+ metricMaker.newCounter(
+ "review_count",
+ new Description("Total number of posted reviews").setRate().setUnit("reviews"));
+ commentCount =
+ metricMaker.newCounter(
+ "comment_count",
+ new Description("Total number of posted review comments")
+ .setRate()
+ .setUnit("comments"));
+ reviewTimer =
+ metricMaker.newTimer(
+ "review_latency",
+ new Description("Time spent posting reviews to revisions")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS));
+ reviewCountByProject =
+ metricMaker.newCounter(
+ "review_count_by_project",
+ new Description("Total number of posted reviews").setRate().setUnit("reviews"),
+ project);
+ commentCountByProject =
+ metricMaker.newCounter(
+ "comment_count_by_project",
+ new Description("Total number of posted review comments").setRate().setUnit("comments"),
+ project);
+ reviewTimerByProject =
+ metricMaker.newTimer(
+ "review_latency_by_project",
+ new Description("Time spent posting reviews to revisions")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS),
+ project);
+ scanRevisionTimer =
+ metricMaker.newTimer(
+ "scan_revision_latency",
+ new Description("Time spent scanning entire revisions")
+ .setCumulative()
+ .setUnit(Units.MILLISECONDS));
+ scanFileTimer =
+ metricMaker.newTimer(
+ "scan_file_latency",
+ new Description("Time spent scanning each file")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS));
+ scanCountByProject =
+ metricMaker.newCounter(
+ "scan_count_by_project",
+ new Description("Total number of copyright scans").setRate().setUnit("scans"),
+ project);
+ scanRevisionTimerByProject =
+ metricMaker.newTimer(
+ "scan_revision_latency_by_project",
+ new Description("Time spent scanning entire revisions")
+ .setCumulative()
+ .setUnit(Units.MILLISECONDS),
+ project);
+ scanFileTimerByProject =
+ metricMaker.newTimer(
+ "scan_file_latency_by_project",
+ new Description("Time spent scanning each file")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS),
+ project);
+ scanCountByBranch =
+ metricMaker.newCounter(
+ "scan_count_by_branch",
+ new Description("Total number of copyright scans").setRate().setUnit("scans"),
+ branch);
+ scanRevisionTimerByBranch =
+ metricMaker.newTimer(
+ "scan_revision_latency_by_branch",
+ new Description("Time spent scanning entire revisions")
+ .setCumulative()
+ .setUnit(Units.MILLISECONDS),
+ branch);
+ scanFileTimerByBranch =
+ metricMaker.newTimer(
+ "scan_file_latency_by_branch",
+ new Description("Time spent scanning each file")
+ .setCumulative()
+ .setUnit(Units.MICROSECONDS),
+ branch);
+ skippedReviewWarnings =
+ metricMaker.newCounter(
+ "skipped_scan_warning_count",
+ new Description("Number revision scans skipped due to configuration problems")
+ .setRate()
+ .setUnit("warnings"),
+ project);
+ scanErrors =
+ metricMaker.newCounter(
+ "failed_scan_error_count",
+ new Description("Number of failed attempts to scan revisions")
+ .setRate()
+ .setUnit("errors"),
+ project);
+ errors =
+ metricMaker.newCounter(
+ "error_count",
+ new Description("Number of errors of any kind").setRate().setUnit("errors"));
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/Module.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/Module.java
index af872c7..7f7bd82 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/Module.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/ScannerConfig.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/ScannerConfig.java
index 815b28c..c53ee1f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/ScannerConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/ScannerConfig.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -33,7 +33,7 @@
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
-/** Configuration state for {@link CopyrightValidator}. */
+/** Configuration state for {@link CopyrightValidator} from All-Projects project.config file. */
class ScannerConfig {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -88,6 +88,7 @@
this.fromAccountId = 0;
}
+ /** True when {@link CopyrightValidator} will behave the same with either config. */
@Override
public boolean equals(Object other) {
if (this == other) {
@@ -99,6 +100,7 @@
if (other instanceof ScannerConfig) {
ScannerConfig otherConfig = (ScannerConfig) other;
return defaultEnable == otherConfig.defaultEnable
+ && fromAccountId == otherConfig.fromAccountId
&& messages.equals(otherConfig.messages)
&& alwaysReviewPath.equals(otherConfig.alwaysReviewPath)
&& matchProjects.equals(otherConfig.matchProjects)
@@ -116,6 +118,7 @@
public int hashCode() {
return Objects.hash(
defaultEnable,
+ fromAccountId,
messages,
alwaysReviewPath,
matchProjects,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/Archive.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/Archive.java
index 8d6ed0b..8d8fab7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/Archive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/Archive.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatterns.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatterns.java
index 060dffc..d2bf243 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatterns.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatterns.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScanner.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScanner.java
index ddc5f78..736a537 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScanner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScanner.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReader.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReader.java
index 015863c..f4749fc 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReader.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScan.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScan.java
index b5591a4..37fed5e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScan.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScan.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/ScanTool.java b/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/ScanTool.java
index 0a4bb04..087f2c3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/ScanTool.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/copyright/tools/ScanTool.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index e700891..a165149 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -14,6 +14,7 @@
It will have false-positives--especially in the unknown category. It may also
have false negatives.
+
## First-party
Licensed or owned by the owner of the gerrit repository.
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 81eec27..b682c71 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -84,6 +84,7 @@
bazel test --test_tag_filters=@PLUGIN@ //...
````
+
This project can be imported into the Eclipse IDE.
Add the plugin name to the `CUSTOM_PLUGINS` set in
Gerrit core in `tools/bzl/plugins.bzl`, and execute:
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 32b4ef9..5163a2d 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -43,6 +43,7 @@
the command-line tool, to take heed of any warnings or errors it prints, and
to copy+paste the token.
+
## Project Configuration
Each project's `project.config` has a configuration parameter to enable or to
@@ -216,7 +217,8 @@
Review comments will appear to come from the given account. Recommend
creating a non-interactive user with a descriptive name like
- "Copyright Scanner".
+ "Copyright Scanner". Must have read access to refs/heads/* and to
+ refs/meta/config in all repositories.
plugin.@PLUGIN@.matchProjects
: List of Project Patterns to Scan
diff --git a/src/main/resources/Documentation/known-patterns.md b/src/main/resources/Documentation/known-patterns.md
index fae7a2d..9499a1e 100644
--- a/src/main/resources/Documentation/known-patterns.md
+++ b/src/main/resources/Documentation/known-patterns.md
@@ -15,3 +15,4 @@
The names do not have to match an exact license or entity per se. For example,
the Creative Commons folks do not define a CC_BY_C license. The named pattern
matches any of several Creative Commons licenses that allow commercial use.
+
diff --git a/src/main/resources/Documentation/modified-regex.md b/src/main/resources/Documentation/modified-regex.md
index 9e1bd9e..8abc2df 100644
--- a/src/main/resources/Documentation/modified-regex.md
+++ b/src/main/resources/Documentation/modified-regex.md
@@ -10,6 +10,7 @@
expressions](https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html)
with modifications to assist the 3 requirements above.
+
## Unlimited Wildcards
If you run the ScanTool.java command-line tool against the files in your
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfigIT.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfigIT.java
index 7a31f07..af7278a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfigIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightConfigIT.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -25,6 +25,7 @@
import static com.googlesource.gerrit.plugins.copyright.TestConfig.LOCAL_BRANCH;
import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
import com.google.common.truth.Correspondence;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.GerritConfigs;
@@ -47,6 +48,8 @@
@TestPlugin(name = "copyright", sysModule = "com.googlesource.gerrit.plugins.copyright.Module")
public class CopyrightConfigIT extends LightweightPluginDaemonTest {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
@Test
@GerritConfigs({
@GerritConfig(name = "plugin.copyright.enable", value = "true"),
@@ -99,7 +102,9 @@
})
public void testCopyrightConfig_pushWithSenderNoName() throws Exception {
TestAccount anonymous =
- accountCreator.create("copyright-scan", "", "", "Non-Interactive Users", expertGroup.name);
+ accountCreator.create(
+ "copyright-scan", "", "", "Administrators", "Non-Interactive Users", expertGroup.name);
+
testConfig.updatePlugin(
cfg -> {
cfg.setInt(KEY_FROM, anonymous.id().get());
@@ -317,6 +322,7 @@
"copyright-scanner",
"copyright-scanner@example.com",
"Copyright Scanner",
+ "Administrators",
"Non-Interactive Users",
expertGroup.name);
reviewer =
@@ -360,16 +366,9 @@
}
private static Correspondence<Comment, String> warningContains() {
- return new Correspondence<Comment, String>() {
- @Override
- public boolean compare(Comment actual, String expected) {
- return actual.message.startsWith("WARNING ") && actual.message.contains(expected);
- }
-
- @Override
- public String toString() {
- return "matches regex";
- }
- };
+ return Correspondence.from(
+ (actual, expected) ->
+ actual.message.startsWith("WARNING ") && actual.message.contains(expected),
+ "matches regex");
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApiTest.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApiTest.java
index f71ea0f..efea843 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApiTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightReviewApiTest.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -39,6 +39,7 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightScanner.Match;
import org.junit.Before;
import org.junit.Test;
@@ -53,21 +54,15 @@
private IdentifiedUser.GenericFactory identifiedUserFactory =
createMock(IdentifiedUser.GenericFactory.class);
+ private ThreadLocalRequestContext requestContext = createMock(ThreadLocalRequestContext.class);
+
private CopyrightReviewApi reviewApi;
@Before
public void setUp() throws Exception {
reviewApi =
new CopyrightReviewApi(
- null,
- () -> pluginUser,
- () -> currentUser,
- identifiedUserFactory,
- null,
- null,
- null,
- null,
- null);
+ null, () -> pluginUser, () -> currentUser, identifiedUserFactory, requestContext, null);
}
@Test
@@ -90,7 +85,7 @@
CurrentUser from = reviewApi.getSendingUser(0);
verify(identifiedUserFactory);
- assertThat(from).isSameAs(currentUser);
+ assertThat(from).isSameInstanceAs(currentUser);
}
@Test
@@ -353,33 +348,18 @@
}
private static Correspondence<CommentInput, CommentInput> startsWithAndRangesMatch() {
- return new Correspondence<CommentInput, CommentInput>() {
- @Override
- public boolean compare(CommentInput actual, CommentInput expected) {
- return actual.range.startLine == expected.range.startLine
- && actual.range.endLine == expected.range.endLine
- && actual.message.startsWith(expected.message);
- }
-
- @Override
- public String toString() {
- return "starts with and ranges match";
- }
- };
+ return Correspondence.from(
+ (actual, expected) ->
+ actual.range.startLine == expected.range.startLine
+ && actual.range.endLine == expected.range.endLine
+ && actual.message.startsWith(expected.message),
+ "starts with and ranges match");
}
private static Correspondence<AddReviewerInput, String> addressedTo() {
- return new Correspondence<AddReviewerInput, String>() {
- @Override
- public boolean compare(AddReviewerInput actual, String expected) {
- return expected.equals(actual.state().toString() + ":" + actual.reviewer);
- }
-
- @Override
- public String toString() {
- return "addressed to";
- }
- };
+ return Correspondence.from(
+ (actual, expected) -> expected.equals(actual.state().toString() + ":" + actual.reviewer),
+ "addressed to");
}
/** Comment input {@code text} from {@code start} line to {@code end} line. */
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidatorIT.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidatorIT.java
index 304e87f..a629e9f 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidatorIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/CopyrightValidatorIT.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -434,17 +434,10 @@
}
private static Correspondence<Comment, CommentMatch> commentContains() {
- return new Correspondence<Comment, CommentMatch>() {
- @Override
- public boolean compare(Comment actual, CommentMatch expected) {
- return actual.unresolved != expected.resolved && actual.message.contains(expected.content);
- }
-
- @Override
- public String toString() {
- return "comment resolution status and content matches";
- }
- };
+ return Correspondence.from(
+ (actual, expected) ->
+ actual.unresolved != expected.resolved && actual.message.contains(expected.content),
+ "comment resolution status and content matches");
}
private static class CommentMatch {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/TestConfig.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/TestConfig.java
index f35cbc0..346c53b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/TestConfig.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/TestConfig.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/ArchiveTest.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/ArchiveTest.java
index c5aeb8d..87e4023 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/ArchiveTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/ArchiveTest.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatternsTest.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatternsTest.java
index a7bd486..394eb76 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatternsTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightPatternsTest.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScannerTest.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScannerTest.java
index 3aa379b..6966975 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScannerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/CopyrightScannerTest.java
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -36,17 +36,7 @@
public class CopyrightScannerTest {
private static final Correspondence<String, String> CONTAINS_STRING =
- new Correspondence<String, String>() {
- @Override
- public boolean compare(String actual, String expected) {
- return actual.contains(expected);
- }
-
- @Override
- public String toString() {
- return "contains";
- }
- };
+ Correspondence.from((actual, expected) -> actual.contains(expected), "contains");
private CopyrightPatterns.RuleSet.Builder builder;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReaderTest.java b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReaderTest.java
index a337027..cdbe089 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReaderTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/lib/IndexedLineReaderTest.java
@@ -4,7 +4,7 @@
// 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
+// 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,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/ANDROID.txt b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/ANDROID.txt
index 71a183b..8ae0bfd 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/ANDROID.txt
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/ANDROID.txt
@@ -1,3 +1,3 @@
/*
- * Copyright (C) 2019 Android Open-Source Project
+ * Copyright (C) 2019 Android Open-Source Project
*/
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/APACHE2.txt b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/APACHE2.txt
index d645695..cb12cf1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/APACHE2.txt
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/APACHE2.txt
@@ -176,6 +176,7 @@
END OF TERMS AND CONDITIONS
+
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/BSD2.txt b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/BSD2.txt
index 453967f..5b4d707 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/BSD2.txt
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/BSD2.txt
@@ -4,6 +4,7 @@
Copyright (c) 2019, Jane Doe <jdoe@example.com>
All rights reserved.
+
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/MIT.txt b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/MIT.txt
index af63709..2a1d858 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/MIT.txt
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/MIT.txt
@@ -12,6 +12,7 @@
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/UNKNOWN.txt b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/UNKNOWN.txt
index 67a5ebe..87124eb 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/UNKNOWN.txt
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/testdata/licenses/UNKNOWN.txt
@@ -1,4 +1,4 @@
#!/bin/sh
# Copyright (C) 2019
-# Jane Doe <jdoe@example.com>
+# Jane Doe <jdoe@example.com>
exit 0
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScanTest.sh b/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScanTest.sh
index cb3a3eb..0e8e5d0 100755
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScanTest.sh
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/AndroidScanTest.sh
@@ -6,7 +6,7 @@
# 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
+# 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,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/ScanToolTest.sh b/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/ScanToolTest.sh
index 89ab77e..1db9039 100755
--- a/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/ScanToolTest.sh
+++ b/src/test/java/com/googlesource/gerrit/plugins/copyright/tools/ScanToolTest.sh
@@ -6,7 +6,7 @@
# 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
+# 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,
diff --git a/tools/android_scan.sh b/tools/android_scan.sh
index a3a51b2..1771f97 100755
--- a/tools/android_scan.sh
+++ b/tools/android_scan.sh
@@ -6,7 +6,7 @@
# 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
+# 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,
diff --git a/tools/check_new_config.sh b/tools/check_new_config.sh
index 01cb7a4..29a7b27 100755
--- a/tools/check_new_config.sh
+++ b/tools/check_new_config.sh
@@ -6,7 +6,7 @@
# 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
+# 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,
@@ -34,7 +34,7 @@
echo
else
echo "The project.config full path must end with project.config -- not $(basename $2)"
- ehco
+ echo
fi
fi
}