aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToni Saario <toni.saario@qt.io>2020-12-11 14:45:13 +0200
committerToni Saario <toni.saario@qt.io>2021-02-16 09:17:05 +0000
commit86d40779ff1d8f45cadeb747213c8eebffcf6d2b (patch)
tree4ee2410e5d1942dc5358eeaa1789e049429b8272
parente8b5ec34e8be5b78ac3c034605169358c597a872 (diff)
Add a button to trigger CI early check
This allow users to start a early check integration from gerrit. Precheck requires that user is able to approve the change. Task-number: QTQAINFRA-3099 Change-Id: Ib5e8188317993f1c7c33e34e333f91648e33ebe9 Reviewed-by: Toni Saario <toni.saario@qt.io> Reviewed-by: Paul Wicking <paul.wicking@qt.io> Reviewed-by: Jukka Jokiniva <jukka.jokiniva@qt.io>
-rw-r--r--qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html3
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtChangePreCheckEvent.java17
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java2
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheck.java133
-rw-r--r--src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java11
-rw-r--r--src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheckIT.java58
6 files changed, 223 insertions, 1 deletions
diff --git a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
index 355193e..cc35cd0 100644
--- a/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
+++ b/qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html
@@ -13,7 +13,8 @@
'gerrit-plugin-qt-workflow~defer',
'gerrit-plugin-qt-workflow~reopen',
'gerrit-plugin-qt-workflow~stage',
- 'gerrit-plugin-qt-workflow~unstage'
+ 'gerrit-plugin-qt-workflow~unstage',
+ 'gerrit-plugin-qt-workflow~precheck'
];
Gerrit.install(plugin => {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtChangePreCheckEvent.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtChangePreCheckEvent.java
new file mode 100644
index 0000000..c076e81
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtChangePreCheckEvent.java
@@ -0,0 +1,17 @@
+//
+// Copyright (C) 2021 The Qt Company
+//
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.events.PatchSetEvent;
+
+public class QtChangePreCheckEvent extends PatchSetEvent {
+ public static final String TYPE = "precheck";
+ public String commitID = "";
+
+ public QtChangePreCheckEvent(Change change) {
+ super(TYPE, change);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java
index a84e47a..a5e0e6e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java
@@ -21,6 +21,7 @@ public class QtModule extends FactoryModule {
static {
EventTypes.register(QtChangeStagedEvent.TYPE, QtChangeStagedEvent.class);
EventTypes.register(QtChangeUnStagedEvent.TYPE, QtChangeUnStagedEvent.class);
+ EventTypes.register(QtChangePreCheckEvent.TYPE, QtChangePreCheckEvent.class);
}
@Override
@@ -39,6 +40,7 @@ public class QtModule extends FactoryModule {
post(CHANGE_KIND, "reopen").to(QtReOpen.class);
post(REVISION_KIND, "stage").to(QtStage.class);
post(REVISION_KIND, "unstage").to(QtUnStage.class);
+ post(REVISION_KIND, "precheck").to(QtPreCheck.class);
}
});
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheck.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheck.java
new file mode 100644
index 0000000..19c215a
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheck.java
@@ -0,0 +1,133 @@
+//
+// Copyright (C) 2021 The Qt Company
+//
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.data.ParameterizedString;
+import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.webui.UiAction;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.change.RevisionResource;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.permissions.LabelPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.LabelPermission.ForUser;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.update.UpdateException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import java.io.IOException;
+import java.util.Map;
+
+@Singleton
+public class QtPreCheck
+ implements RestModifyView<RevisionResource, SubmitInput>, UiAction<RevisionResource> {
+
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private static final String DEFAULT_TOOLTIP = "Trigger a precheck integration";
+ private static final String LABEL_CODE_REVIEW = "Code-Review";
+ private static final short LABEL_CODE_REVIEW_VALUE = 2;
+
+ public static class Output {
+ transient Change change;
+
+ private Output(Change c) {
+ change = c;
+ }
+ }
+
+ private final PermissionBackend permissionBackend;
+ private final ChangeData.Factory changeDataFactory;
+ private final QtUtil qtUtil;
+ private final String label;
+ private final ParameterizedString titlePattern;
+
+ private Change change;
+
+ @Inject
+ QtPreCheck(
+ PermissionBackend permissionBackend,
+ @GerritServerConfig Config cfg,
+ ChangeData.Factory changeDataFactory,
+ QtUtil qtUtil) {
+
+ this.permissionBackend = permissionBackend;
+ this.changeDataFactory = changeDataFactory;
+ this.qtUtil = qtUtil;
+ this.label = "PreCheck";
+ this.titlePattern =
+ new ParameterizedString(
+ MoreObjects.firstNonNull(
+ cfg.getString("precheck", null, "precheckTooltip"), DEFAULT_TOOLTIP));
+ }
+
+ @Override
+ public Response<Output> apply(RevisionResource rsrc, SubmitInput input)
+ throws RestApiException, RepositoryNotFoundException, IOException, PermissionBackendException,
+ UpdateException, ConfigInvalidException {
+ logger.atInfo().log("qtcodereview: precheck request for %s", rsrc.getChange().toString());
+ boolean canReview;
+
+ canReview = rsrc.permissions().test(new LabelPermission.
+ WithValue(ForUser.SELF, LABEL_CODE_REVIEW, LABEL_CODE_REVIEW_VALUE));
+
+ if (!canReview) {
+ throw new AuthException(String.format("Precheck request from user %s without permission, %s",
+ rsrc.getUser().getUserName(), rsrc.getChange().toString()));
+ }
+
+ Change change = rsrc.getChange();
+ Output output;
+ output = new Output(change);
+ this.qtUtil.postChangePreCheckEvent(change, rsrc.getPatchSet());
+ return Response.ok(output);
+ }
+
+ @Override
+ public UiAction.Description getDescription(RevisionResource resource) {
+ boolean canReview;
+ try {
+ canReview = resource.permissions().test(new LabelPermission
+ .WithValue(ForUser.SELF, LABEL_CODE_REVIEW, LABEL_CODE_REVIEW_VALUE));
+ } catch (PermissionBackendException e) {
+ logger.atInfo().log(e.getMessage());
+ return null;
+ }
+
+ if (!canReview) {
+ return null;
+ }
+
+ Change change = resource.getChange();
+ if (!change.getStatus().isOpen()
+ || !resource.isCurrent()) {
+ return null; // precheck not visible
+ }
+
+ ObjectId revId = resource.getPatchSet().commitId();
+ Map<String, String> params =
+ ImmutableMap.of(
+ "patchSet", String.valueOf(resource.getPatchSet().number()),
+ "branch", change.getDest().shortName(),
+ "commit", revId.abbreviate(7).name());
+ return new UiAction.Description()
+ .setLabel(this.label)
+ .setTitle(Strings.emptyToNull(titlePattern.replace(params)))
+ .setVisible(true)
+ .setEnabled(true);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
index fc09ac5..459c345 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtUtil.java
@@ -682,4 +682,15 @@ public class QtUtil {
}
}
+ public void postChangePreCheckEvent(Change change, PatchSet patchSet) {
+ try {
+ ChangeNotes notes = changeNotesFactory.createChecked(change.getId());
+ QtChangePreCheckEvent event = new QtChangePreCheckEvent(change);
+ event.change = changeAttributeSupplier(change, notes);
+ event.commitID = patchSet.commitId().name();
+ eventDispatcher.get().postEvent(event);
+ } catch (StorageException | PermissionBackendException e) {
+ logger.atWarning().log("qtcodereview: postChangePreCheckEvent failed: %s", e);
+ }
+ }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheckIT.java b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheckIT.java
new file mode 100644
index 0000000..5519c1a
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtPreCheckIT.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 The Qt Company
+
+package com.googlesource.gerrit.plugins.qtcodereview;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
+
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.entities.AccountGroup;
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+@TestPlugin(
+ name = "gerrit-plugin-qt-workflow",
+ sysModule = "com.googlesource.gerrit.plugins.qtcodereview.QtModule",
+ sshModule = "com.googlesource.gerrit.plugins.qtcodereview.QtSshModule")
+
+@UseSsh
+public class QtPreCheckIT extends QtCodeReviewIT {
+
+ @Test
+ public void preCheck_Ok() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ AccountGroup.UUID registered = systemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
+ projectOperations.project(project).forUpdate()
+ .add(allowLabel("Code-Review").ref("refs/heads/*").group(registered).range(-2, 2))
+ .update();
+
+ RestResponse response = call_REST_API_PreCheck(c.getChangeId(), c.getCommit().getName());
+ response.assertOK();
+ }
+
+ @Test
+ public void errorPreCheck_No_Permission() throws Exception {
+ PushOneCommit.Result c = pushCommit("master", "commitmsg1", "file1", "content1");
+
+ AccountGroup.UUID registered = systemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
+ projectOperations.project(project).forUpdate()
+ .add(allowLabel("Code-Review").ref("refs/heads/*").group(registered).range(-1, 1))
+ .update();
+
+ RestResponse response = call_REST_API_PreCheck(c.getChangeId(), c.getCommit().getName());
+ response.assertStatus(HttpStatus.SC_FORBIDDEN);
+ }
+
+ protected RestResponse call_REST_API_PreCheck(String changeId, String revisionId)
+ throws Exception {
+ String url =
+ "/changes/" + changeId + "/revisions/" + revisionId + "/gerrit-plugin-qt-workflow~precheck";
+ RestResponse response = userRestSession.post(url);
+ return response;
+ }
+
+}