Merge "Do not fail import if hashtags cannot be set due to missing permissions"
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
index eb7d2e0..eef151a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
@@ -18,6 +18,7 @@
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.errors.NoSuchAccountException;
+import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -35,6 +36,9 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -46,6 +50,9 @@
AddApprovalsStep create(Change change, ChangeInfo changeInfo, boolean resume);
}
+ private static final Logger log = LoggerFactory
+ .getLogger(ReplayInlineCommentsStep.class);
+
private final AccountUtil accountUtil;
private final ChangeUpdate.Factory updateFactory;
private final ReviewDb db;
@@ -54,6 +61,7 @@
private final Change change;
private final ChangeInfo changeInfo;
private final boolean resume;
+ private final String pluginName;
@Inject
public AddApprovalsStep(AccountUtil accountUtil,
@@ -61,6 +69,7 @@
ReviewDb db,
IdentifiedUser.GenericFactory genericUserFactory,
ChangeControl.GenericFactory changeControlFactory,
+ @PluginName String pluginName,
@Assisted Change change,
@Assisted ChangeInfo changeInfo,
@Assisted boolean resume) {
@@ -72,6 +81,7 @@
this.change = change;
this.changeInfo = changeInfo;
this.resume = resume;
+ this.pluginName = pluginName;
}
void add(RemoteApi api) throws OrmException, NoSuchChangeException, IOException,
@@ -90,6 +100,15 @@
Account.Id user = accountUtil.resolveUser(api, a);
ChangeControl ctrl = control(change, a);
LabelType labelType = ctrl.getLabelTypes().byLabel(labelName);
+ if(labelType == null) {
+ log.warn(String.format("[%s] Label '%s' not found in target system."
+ + " This label was referenced by an approval provided from '%s'"
+ + " for change '%s'."
+ + " This approval will be skipped. In order to import this"
+ + " approval configure the missing label and resume the import."
+ , pluginName, labelName, a.username, changeInfo.id));
+ continue;
+ }
approvals.add(new PatchSetApproval(
new PatchSetApproval.Key(change.currentPatchSetId(), user,
labelType.getLabelId()), a.value.shortValue(),
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
index 7cb35ac..81363e7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
@@ -15,12 +15,21 @@
package com.googlesource.gerrit.plugins.importer;
import com.google.gerrit.extensions.annotations.PluginData;
+import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.googlesource.gerrit.plugins.importer.CompleteProjectImport.Input;
@@ -67,4 +76,57 @@
throw new ResourceConflictException("failed to lock project for delete");
}
}
+
+ public static class OnProjects implements
+ RestModifyView<ProjectResource, Input>, UiAction<ProjectResource> {
+ private final ProjectsCollection projectsCollection;
+ private final CompleteProjectImport completeProjectImport;
+ private final Provider<CurrentUser> currentUserProvider;
+ private final String pluginName;
+
+ @Inject
+ public OnProjects(ProjectsCollection projectsCollection,
+ CompleteProjectImport completeProjectImport,
+ Provider<CurrentUser> currentUserProvider,
+ @PluginName String pluginName) {
+ this.projectsCollection = projectsCollection;
+ this.completeProjectImport = completeProjectImport;
+ this.currentUserProvider = currentUserProvider;
+ this.pluginName = pluginName;
+ }
+
+ @Override
+ public Response<?> apply(ProjectResource rsrc, Input input)
+ throws ResourceNotFoundException, ResourceConflictException {
+ ImportProjectResource projectResource =
+ projectsCollection.parse(new ConfigResource(),
+ IdString.fromDecoded(rsrc.getName()));
+ return completeProjectImport.apply(projectResource, input);
+ }
+
+ @Override
+ public UiAction.Description getDescription(ProjectResource rsrc) {
+ UiAction.Description desc = new UiAction.Description()
+ .setLabel("Complete Import...")
+ .setTitle("Complete the project import."
+ + " After completion, resume is not possible anymore.");
+
+ try {
+ projectsCollection.parse(new ConfigResource(),
+ IdString.fromDecoded(rsrc.getName()));
+ desc.setVisible(canCompleteImport(rsrc));
+ } catch (ResourceNotFoundException e) {
+ desc.setVisible(false);
+ }
+
+ return desc;
+ }
+
+ private boolean canCompleteImport(ProjectResource rsrc) {
+ CapabilityControl ctl = currentUserProvider.get().getCapabilities();
+ return ctl.canAdministrateServer()
+ || (ctl.canPerform(pluginName + "-" + ImportCapability.ID)
+ && rsrc.getControl().isOwner());
+ }
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpModule.java
index 7a5bdfc..7b6edf0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpModule.java
@@ -29,6 +29,8 @@
.toInstance(new JavaScriptPlugin("resume-copy-project.js"));
DynamicSet.bind(binder(), WebUiPlugin.class)
.toInstance(new JavaScriptPlugin("resume-project-import.js"));
+ DynamicSet.bind(binder(), WebUiPlugin.class)
+ .toInstance(new JavaScriptPlugin("complete-project-import.js"));
DynamicSet.bind(binder(), WebUiPlugin.class)
.toInstance(new GwtPlugin("importer"));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
index d703aa8..0a121be 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
@@ -52,6 +52,7 @@
put(PROJECT_KIND, "copy").to(CopyProject.class);
put(PROJECT_KIND, "copy.resume").to(ResumeCopyProject.class);
put(PROJECT_KIND, "import.resume").to(ResumeProjectImport.OnProjects.class);
+ post(PROJECT_KIND, "delete").to(CompleteProjectImport.OnProjects.class);
child(CONFIG_KIND, "groups").to(GroupsCollection.class);
}
diff --git a/src/main/resources/Documentation/rest-api-projects.md b/src/main/resources/Documentation/rest-api-projects.md
index ebc443f..252b33d 100644
--- a/src/main/resources/Documentation/rest-api-projects.md
+++ b/src/main/resources/Documentation/rest-api-projects.md
@@ -73,6 +73,25 @@
}
```
+### <a id="complete-project-import"> Complete Project Import
+_POST /projects/[\{project-name\}](../../../Documentation/rest-api-projects.html#project-name)/@PLUGIN@~delete)_
+
+Mark a project import as completed.
+
+Once a project import is completed it cannot be resumed any more.
+
+#### Request
+
+```
+ POST /projects/myProject/@PLUGIN@~delete HTTP/1.0
+```
+
+#### Response
+
+```
+ HTTP/1.1 204 No Content
+```
+
<a id="json-entities">JSON Entities
-----------------------------------
diff --git a/src/main/resources/static/complete-project-import.js b/src/main/resources/static/complete-project-import.js
new file mode 100644
index 0000000..059dc46
--- /dev/null
+++ b/src/main/resources/static/complete-project-import.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2015 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.
+
+Gerrit.install(function(self) {
+ function onCompleteProjectImport(c) {
+ var b = c.button('Complete',
+ {onclick: function(){
+ c.call(
+ {},
+ function(r) {
+ c.hide();
+ window.alert('Import for project "'
+ + c.project
+ + '" was completed."'),
+ Gerrit.go('/admin/projects/' + c.project);
+ });
+ }});
+ c.popup(c.div(
+ c.msg('Complete import for project "'
+ + c.project
+ + '" ?'),
+ c.br(),
+ c.br(),
+ b));
+ }
+ self.onAction('project', 'delete', onCompleteProjectImport);
+ });