diff options
author | Toni Saario <toni.saario@qt.io> | 2020-12-11 14:45:13 +0200 |
---|---|---|
committer | Toni Saario <toni.saario@qt.io> | 2021-02-16 09:17:05 +0000 |
commit | 86d40779ff1d8f45cadeb747213c8eebffcf6d2b (patch) | |
tree | 4ee2410e5d1942dc5358eeaa1789e049429b8272 | |
parent | e8b5ec34e8be5b78ac3c034605169358c597a872 (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>
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; + } + +} |