diff --git a/pom.xml b/pom.xml
index 155fe6d..f2795f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.ngs.stash.externalhooks
external-hooks
- 7.5.0
+ 8.0.0
reconquest
@@ -149,7 +149,7 @@
UTF-8
- 6.6.1
+ 6.8.0
${bitbucket.version}
3.0.5
8.0.1
diff --git a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalAsyncPostReceiveHook.java b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalAsyncPostReceiveHook.java
index 5d87c27..53c2cff 100644
--- a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalAsyncPostReceiveHook.java
+++ b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalAsyncPostReceiveHook.java
@@ -37,6 +37,7 @@ public class ExternalAsyncPostReceiveHook
private ExternalHookScript externalHookScript;
private RepositoryHookService repositoryHookService;
+ public static final String KEY_ID = "external-post-receive-hook";
public ExternalAsyncPostReceiveHook(
AuthenticationContext authenticationContext,
@@ -51,6 +52,27 @@ public ExternalAsyncPostReceiveHook(
throws IOException {
this.repositoryHookService = repositoryHookService;
+ this.externalHookScript = getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
+ }
+
+ public static ExternalHookScript getExternalHookScript(
+ AuthenticationContext authenticationContext,
+ PermissionService permissions,
+ PluginLicenseManager pluginLicenseManager,
+ ClusterService clusterService,
+ StorageService storageProperties,
+ HookScriptService hookScriptService,
+ PluginSettingsFactory pluginSettingsFactory,
+ SecurityService securityService)
+ throws IOException {
List triggers = new ArrayList();
triggers.add(StandardRepositoryHookTrigger.REPO_PUSH);
triggers.add(StandardRepositoryHookTrigger.FILE_EDIT);
@@ -60,7 +82,7 @@ public ExternalAsyncPostReceiveHook(
triggers.add(StandardRepositoryHookTrigger.BRANCH_CREATE);
triggers.add(StandardRepositoryHookTrigger.PULL_REQUEST_MERGE);
- this.externalHookScript = new ExternalHookScript(
+ return new ExternalHookScript(
authenticationContext,
permissions,
pluginLicenseManager,
@@ -69,7 +91,7 @@ public ExternalAsyncPostReceiveHook(
hookScriptService,
pluginSettingsFactory,
securityService,
- "external-post-receive-hook",
+ KEY_ID,
HookScriptType.POST,
triggers);
}
diff --git a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalHookScript.java b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalHookScript.java
index 194e898..48ff362 100644
--- a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalHookScript.java
+++ b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalHookScript.java
@@ -41,11 +41,12 @@
public class ExternalHookScript {
public static final String PLUGIN_KEY = "com.ngs.stash.externalhooks.external-hooks";
+
private final PluginLicenseManager pluginLicenseManager;
private static Logger log = LoggerFactory.getLogger(ExternalHookScript.class.getSimpleName());
public final Escaper SHELL_ESCAPE;
private AuthenticationContext authCtx;
- private PermissionService permissions;
+ private PermissionService permissionService;
private ClusterService clusterService;
private StorageService storageProperties;
private HookScriptService hookScriptService;
@@ -59,7 +60,7 @@ public class ExternalHookScript {
public ExternalHookScript(
AuthenticationContext authenticationContext,
- PermissionService permissions,
+ PermissionService permissionService,
PluginLicenseManager pluginLicenseManager,
ClusterService clusterService,
StorageService storageProperties,
@@ -71,7 +72,7 @@ public ExternalHookScript(
List repositoryHookTriggers)
throws IOException {
this.authCtx = authenticationContext;
- this.permissions = permissions;
+ this.permissionService = permissionService;
this.storageProperties = storageProperties;
this.pluginLicenseManager = pluginLicenseManager;
this.clusterService = clusterService;
@@ -90,6 +91,10 @@ public ExternalHookScript(
this.hookScriptTemplate = this.getResource("hook-script.template.bash");
}
+ public String getHookKey() {
+ return this.hookId;
+ }
+
private String getResource(String name) throws IOException {
InputStream resource = ClassLoaderUtils.getResourceAsStream(name, this.getClass());
if (resource == null) {
@@ -128,7 +133,7 @@ public void validate(
}
if (!settings.getBoolean("safe_path", false)) {
- if (!permissions.hasGlobalPermission(Permission.SYS_ADMIN)) {
+ if (!permissionService.hasGlobalPermission(Permission.SYS_ADMIN)) {
errors.addFieldError(
"exe", "You should be a Bitbucket System Administrator to edit this field "
+ "without \"safe mode\" option.");
@@ -244,7 +249,7 @@ public void install(@Nonnull Settings settings, @Nonnull Scope scope) {
HookScriptSetConfigurationRequest hookScriptSetConfigurationRequest = configBuilder.build();
hookScriptService.setConfiguration(hookScriptSetConfigurationRequest);
- log.info("Successfully created HookScript with id: {}", hookScript.getId());
+ log.warn("Created HookScript with id: {}", hookScript.getId());
}
public File getExecutable(String path, boolean safeDir) {
diff --git a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalMergeCheckHook.java b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalMergeCheckHook.java
index 5d130a9..be32299 100644
--- a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalMergeCheckHook.java
+++ b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalMergeCheckHook.java
@@ -36,6 +36,7 @@
public class ExternalMergeCheckHook implements RepositoryMergeCheck, SettingsValidator {
private ExternalHookScript externalHookScript;
private RepositoryHookService repositoryHookService;
+ public static final String KEY_ID = "external-merge-check-hook";
public ExternalMergeCheckHook(
AuthenticationContext authenticationContext,
@@ -49,11 +50,33 @@ public ExternalMergeCheckHook(
SecurityService securityService)
throws IOException {
+ this.repositoryHookService = repositoryHookService;
+
+ this.externalHookScript = getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
+ }
+
+ public static ExternalHookScript getExternalHookScript(
+ AuthenticationContext authenticationContext,
+ PermissionService permissions,
+ PluginLicenseManager pluginLicenseManager,
+ ClusterService clusterService,
+ StorageService storageProperties,
+ HookScriptService hookScriptService,
+ PluginSettingsFactory pluginSettingsFactory,
+ SecurityService securityService)
+ throws IOException {
List triggers = new ArrayList();
triggers.add(StandardRepositoryHookTrigger.PULL_REQUEST_MERGE);
- this.repositoryHookService = repositoryHookService;
- this.externalHookScript = new ExternalHookScript(
+ return new ExternalHookScript(
authenticationContext,
permissions,
pluginLicenseManager,
@@ -62,7 +85,7 @@ public ExternalMergeCheckHook(
hookScriptService,
pluginSettingsFactory,
securityService,
- "external-merge-check-hook",
+ KEY_ID,
HookScriptType.PRE,
triggers);
}
diff --git a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalPreReceiveHook.java b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalPreReceiveHook.java
index 4925e2c..dd2d8f2 100644
--- a/src/main/java/com/ngs/stash/externalhooks/hook/ExternalPreReceiveHook.java
+++ b/src/main/java/com/ngs/stash/externalhooks/hook/ExternalPreReceiveHook.java
@@ -37,6 +37,7 @@ public class ExternalPreReceiveHook
implements PreRepositoryHook, SettingsValidator {
private ExternalHookScript externalHookScript;
+ public static final String KEY_ID = "external-pre-receive-hook";
private RepositoryHookService repositoryHookService;
@@ -51,6 +52,28 @@ public ExternalPreReceiveHook(
RepositoryHookService repositoryHookService,
SecurityService securityService)
throws IOException {
+ this.repositoryHookService = repositoryHookService;
+ this.externalHookScript = getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
+ }
+
+ public static ExternalHookScript getExternalHookScript(
+ AuthenticationContext authenticationContext,
+ PermissionService permissions,
+ PluginLicenseManager pluginLicenseManager,
+ ClusterService clusterService,
+ StorageService storageProperties,
+ HookScriptService hookScriptService,
+ PluginSettingsFactory pluginSettingsFactory,
+ SecurityService securityService)
+ throws IOException {
List triggers = new ArrayList();
triggers.add(StandardRepositoryHookTrigger.REPO_PUSH);
triggers.add(StandardRepositoryHookTrigger.FILE_EDIT);
@@ -58,9 +81,7 @@ public ExternalPreReceiveHook(
triggers.add(StandardRepositoryHookTrigger.TAG_CREATE);
triggers.add(StandardRepositoryHookTrigger.BRANCH_DELETE);
triggers.add(StandardRepositoryHookTrigger.BRANCH_CREATE);
-
- this.repositoryHookService = repositoryHookService;
- this.externalHookScript = new ExternalHookScript(
+ return new ExternalHookScript(
authenticationContext,
permissions,
pluginLicenseManager,
@@ -69,7 +90,7 @@ public ExternalPreReceiveHook(
hookScriptService,
pluginSettingsFactory,
securityService,
- "external-pre-receive-hook",
+ KEY_ID,
HookScriptType.PRE,
triggers);
}
diff --git a/src/main/java/com/ngs/stash/externalhooks/hook/listeners/ExternalHooksListener.java b/src/main/java/com/ngs/stash/externalhooks/hook/listeners/ExternalHooksListener.java
index ca43dbe..cd80eaa 100644
--- a/src/main/java/com/ngs/stash/externalhooks/hook/listeners/ExternalHooksListener.java
+++ b/src/main/java/com/ngs/stash/externalhooks/hook/listeners/ExternalHooksListener.java
@@ -1,11 +1,14 @@
package com.ngs.stash.externalhooks.hook.listeners;
+import java.io.IOException;
+
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
-import com.atlassian.bitbucket.hook.repository.EnableRepositoryHookRequest;
+import com.atlassian.bitbucket.auth.AuthenticationContext;
+import com.atlassian.bitbucket.cluster.ClusterService;
import com.atlassian.bitbucket.hook.repository.GetRepositoryHookSettingsRequest;
import com.atlassian.bitbucket.hook.repository.RepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookSearchRequest;
@@ -14,6 +17,7 @@
import com.atlassian.bitbucket.hook.repository.RepositoryHookType;
import com.atlassian.bitbucket.hook.script.HookScriptService;
import com.atlassian.bitbucket.permission.Permission;
+import com.atlassian.bitbucket.permission.PermissionService;
import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.project.ProjectService;
import com.atlassian.bitbucket.repository.Repository;
@@ -21,6 +25,8 @@
import com.atlassian.bitbucket.scope.ProjectScope;
import com.atlassian.bitbucket.scope.RepositoryScope;
import com.atlassian.bitbucket.scope.Scope;
+import com.atlassian.bitbucket.server.StorageService;
+import com.atlassian.bitbucket.setting.Settings;
import com.atlassian.bitbucket.user.SecurityService;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
@@ -37,7 +43,11 @@
import com.atlassian.scheduler.config.JobId;
import com.atlassian.scheduler.config.JobRunnerKey;
import com.atlassian.scheduler.config.Schedule;
+import com.atlassian.upm.api.license.PluginLicenseManager;
+import com.ngs.stash.externalhooks.hook.ExternalAsyncPostReceiveHook;
import com.ngs.stash.externalhooks.hook.ExternalHookScript;
+import com.ngs.stash.externalhooks.hook.ExternalMergeCheckHook;
+import com.ngs.stash.externalhooks.hook.ExternalPreReceiveHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,32 +60,89 @@ public class ExternalHooksListener implements JobRunner {
private final int jobInterval = 2000;
private final JobId jobId = JobId.of("external-hooks-enable-job");
- private final String hookKeyPrefix = "com.ngs.stash.externalhooks.external-hooks:";
-
- private HookScriptService hookScriptService;
- private SecurityService securityService;
- private RepositoryHookService repoHookService;
- private ProjectService projectService;
- private SchedulerService schedulerService;
- private RepositoryService repositoryService;
+
+ @ComponentImport private RepositoryService repositoryService;
+ @ComponentImport private SchedulerService schedulerService;
+ @ComponentImport private HookScriptService hookScriptService;
+ @ComponentImport private RepositoryHookService repoHookService;
+ @ComponentImport private ProjectService projectService;
+ @ComponentImport private PluginSettingsFactory pluginSettingsFactory;
+ @ComponentImport private SecurityService securityService;
+ @ComponentImport private AuthenticationContext authenticationContext;
+
+ @ComponentImport("permissions")
+ private PermissionService permissions;
+
+ @ComponentImport private PluginLicenseManager pluginLicenseManager;
+
+ @ComponentImport private ClusterService clusterService;
+ @ComponentImport private StorageService storageProperties;
+
private PluginSettings pluginSettings;
+ private ExternalHookScript hookPreReceive;
+ private ExternalHookScript hookPostReceive;
+ private ExternalHookScript hookMergeCheck;
+
@Inject
public ExternalHooksListener(
- @ComponentImport RepositoryService repositoryService,
- @ComponentImport SchedulerService schedulerService,
- @ComponentImport HookScriptService hookScriptService,
- @ComponentImport RepositoryHookService repoHookService,
- @ComponentImport ProjectService projectService,
- @ComponentImport PluginSettingsFactory pluginSettingsFactory,
- @ComponentImport SecurityService securityService) {
+ RepositoryService repositoryService,
+ SchedulerService schedulerService,
+ HookScriptService hookScriptService,
+ RepositoryHookService repoHookService,
+ ProjectService projectService,
+ PluginSettingsFactory pluginSettingsFactory,
+ SecurityService securityService,
+ AuthenticationContext authenticationContext,
+ PermissionService permissions,
+ PluginLicenseManager pluginLicenseManager,
+ ClusterService clusterService,
+ StorageService storageProperties)
+ throws IOException {
+ this.repositoryService = repositoryService;
this.schedulerService = schedulerService;
this.hookScriptService = hookScriptService;
this.repoHookService = repoHookService;
this.projectService = projectService;
+ this.pluginSettingsFactory = pluginSettingsFactory;
this.securityService = securityService;
+ this.authenticationContext = authenticationContext;
+ this.permissions = permissions;
+ this.pluginLicenseManager = pluginLicenseManager;
+ this.clusterService = clusterService;
+ this.storageProperties = storageProperties;
+
this.pluginSettings = pluginSettingsFactory.createGlobalSettings();
- this.repositoryService = repositoryService;
+
+ this.hookPreReceive = ExternalPreReceiveHook.getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
+
+ this.hookPostReceive = ExternalAsyncPostReceiveHook.getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
+
+ this.hookMergeCheck = ExternalMergeCheckHook.getExternalHookScript(
+ authenticationContext,
+ permissions,
+ pluginLicenseManager,
+ clusterService,
+ storageProperties,
+ hookScriptService,
+ pluginSettingsFactory,
+ securityService);
}
@PostConstruct
@@ -127,7 +194,7 @@ protected boolean isPluginLoaded() {
boolean found = false;
for (RepositoryHook hook : page.getValues()) {
- if (hook.getDetails().getKey().startsWith(this.hookKeyPrefix)) {
+ if (hook.getDetails().getKey().startsWith(ExternalHookScript.PLUGIN_KEY)) {
found = true;
break;
}
@@ -221,7 +288,8 @@ protected void createHookScripts(Scope scope) {
Integer created = 0;
for (RepositoryHook hook : page.getValues()) {
- if (!hook.getDetails().getKey().startsWith(this.hookKeyPrefix)) {
+ String hookKey = hook.getDetails().getKey();
+ if (!hookKey.startsWith(ExternalHookScript.PLUGIN_KEY)) {
continue;
}
@@ -235,32 +303,43 @@ protected void createHookScripts(Scope scope) {
if (hook.getScope().getType() != scope.getType()) {
log.warn(
- "external-hooks: hook {} is enabled & configured (inherited: {} {})",
- hook.getDetails().getKey(),
+ "Hook {} is enabled & configured (inherited: {} {})",
+ hookKey,
hook.getScope().getType(),
hook.getScope().getResourceId().orElse(-1));
continue;
}
- EnableRepositoryHookRequest.Builder enableHookBuilder =
- new EnableRepositoryHookRequest.Builder(scope, hook.getDetails().getKey());
-
GetRepositoryHookSettingsRequest.Builder getSettingsBuilder =
- new GetRepositoryHookSettingsRequest.Builder(scope, hook.getDetails().getKey());
+ new GetRepositoryHookSettingsRequest.Builder(scope, hookKey);
- RepositoryHookSettings settings =
+ RepositoryHookSettings hookSettings =
this.repoHookService.getSettings(getSettingsBuilder.build());
- if (settings != null) {
- enableHookBuilder.settings(settings.getSettings());
+ if (hookSettings == null) {
+ log.warn("Hook {} has no settings, can't be enabled", hookKey);
+ return;
}
+ Settings settings = hookSettings.getSettings();
+
try {
- log.warn("external-hooks: creating HookScript for {}", hook.getDetails().getKey());
- this.repoHookService.enable(enableHookBuilder.build());
+ if (hookKey.equals(hookPreReceive.getHookKey())) {
+ log.warn("Creating PRE_RECEIVE HookScript for {}", hookKey);
+ this.hookPreReceive.install(settings, scope);
+ } else if (hookKey.equals(hookPostReceive.getHookKey())) {
+ log.warn("Creating POST_RECEIVE HookScript for {}", hookKey);
+ this.hookPostReceive.install(settings, scope);
+ } else if (hookKey.equals(hookMergeCheck.getHookKey())) {
+ log.warn("Creating MERGE_CHECK HookScript for {}", hookKey);
+ this.hookMergeCheck.install(settings, scope);
+ } else {
+ log.warn("Unexpected hook key: {}", hookKey);
+ }
+
created++;
} catch (Exception e) {
- log.error("unable to enable hook: {}", e.toString());
+ log.error("Unable to install hook script {}: {}", hookKey, e.toString());
}
}
diff --git a/testutils/issue100 b/testutils/issue100
old mode 100644
new mode 100755
index 2c840ab..b07d575
--- a/testutils/issue100
+++ b/testutils/issue100
@@ -2,6 +2,7 @@
set -euo pipefail
+cd "$(dirname "$0")"
URI="${URI:-http://admin:admin@localhost:7990/bitbucket}"
stacket --uri "$URI" projects create pwrwo || true