diff --git a/README.md b/README.md
index c816ef9..44bc969 100644
--- a/README.md
+++ b/README.md
@@ -5,11 +5,12 @@
The following is a plugin for Atlassian Stash to provide repository mirroring to a remote repository.
-* atlas-run -- installs this plugin into the product and starts it on localhost
-* atlas-debug -- same as atlas-run, but allows a debugger to attach at port 5005
-* atlas-cli -- after atlas-run or atlas-debug, opens a Maven command line window:
+* `atlas-run` -- installs this plugin into the product and starts it on localhost
+* `atlas-debug` -- same as `atlas-run`, but allows a debugger to attach at port 5005
+* `atlas-debug --jvm-debug-suspend` -- same as `atlas-debug` but waits for the debugger to attach
+* `atlas-cli` -- after atlas-run or atlas-debug, opens a Maven command line window:
- 'pi' reinstalls the plugin into the running product instance
-* atlas-help -- prints description for all commands in the SDK
+* `atlas-help` -- prints description for all commands in the SDK
Full documentation is always available at:
diff --git a/pom.xml b/pom.xml
index 1aa2275..0a2984d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,7 @@
atlassian-plugin
+ UTF-8
2.3.1
2.3.1
4.1.7
@@ -100,6 +101,11 @@
${common-lang.version}
+
+ com.atlassian.stash
+ stash-service-impl
+ test
+
com.atlassian.plugins
atlassian-plugins-osgi-testrunner
diff --git a/src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java b/src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java
new file mode 100644
index 0000000..00110da
--- /dev/null
+++ b/src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java
@@ -0,0 +1,36 @@
+package com.englishtown.stash.hook;
+
+import com.atlassian.stash.setting.Settings;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+/**
+ * Default implementation of {@link SettingsReflectionHelper}
+ */
+public class DefaultSettingsReflectionHelper implements SettingsReflectionHelper {
+
+ /**
+ * Set the values field of the {@link Settings} via reflection
+ *
+ * @param values the values to set
+ * @param settings the settings to set the values field on
+ */
+ @Override
+ public void set(Map values, Settings settings) {
+
+ try {
+ Field field = settings.getClass().getDeclaredField("values");
+ field.setAccessible(true);
+ field.set(settings, values);
+
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
+ "hook.", e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
+ "hook.", e);
+ }
+
+ }
+}
diff --git a/src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java b/src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java
index 484d923..7cd9636 100644
--- a/src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java
+++ b/src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java
@@ -18,18 +18,22 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
-import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, RepositorySettingsValidator {
+ protected static class MirrorSettings {
+ String mirrorRepoUrl;
+ String username;
+ String password;
+ String suffix;
+ }
+
public static final String PLUGIN_SETTINGS_KEY = "com.englishtown.stash.hook.mirror";
static final String SETTING_MIRROR_REPO_URL = "mirrorRepoUrl";
static final String SETTING_USERNAME = "username";
@@ -40,6 +44,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
private final I18nService i18nService;
private final ScheduledExecutorService executor;
private final PasswordEncryptor passwordEncryptor;
+ private final SettingsReflectionHelper settingsReflectionHelper;
private static final Logger logger = LoggerFactory.getLogger(MirrorRepositoryHook.class);
public MirrorRepositoryHook(
@@ -47,6 +52,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
I18nService i18nService,
ScheduledExecutorService executor,
PasswordEncryptor passwordEncryptor,
+ SettingsReflectionHelper settingsReflectionHelper,
PluginSettingsFactory pluginSettingsFactory
) {
logger.debug("MirrorRepositoryHook: init started");
@@ -56,6 +62,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
this.i18nService = i18nService;
this.executor = executor;
this.passwordEncryptor = passwordEncryptor;
+ this.settingsReflectionHelper = settingsReflectionHelper;
// Init password encryptor
PluginSettings pluginSettings = pluginSettingsFactory.createSettingsForKey(PLUGIN_SETTINGS_KEY);
@@ -82,20 +89,19 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
logger.debug("MirrorRepositoryHook: postReceive started.");
- Settings settings = context.getSettings();
- String mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL);
- String username = settings.getString(SETTING_USERNAME);
- String password = settings.getString(SETTING_PASSWORD);
+ List mirrorSettings = getMirrorSettings(context.getSettings());
- runMirrorCommand(mirrorRepoUrl, username, password, context.getRepository());
+ for (MirrorSettings settings : mirrorSettings) {
+ runMirrorCommand(settings, context.getRepository());
+ }
}
- void runMirrorCommand(String mirrorRepoUrl, String username, final String encryptedPassword, final Repository repository) {
+ void runMirrorCommand(MirrorSettings settings, final Repository repository) {
try {
- final String password = passwordEncryptor.decrypt(encryptedPassword);
- final URI authenticatedUrl = getAuthenticatedUrl(mirrorRepoUrl, username, password);
+ final String password = passwordEncryptor.decrypt(settings.password);
+ final URI authenticatedUrl = getAuthenticatedUrl(settings.mirrorRepoUrl, settings.username, password);
executor.submit(new Callable() {
@@ -140,7 +146,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
}
- URI getAuthenticatedUrl(String mirrorRepoUrl, String username, String password) throws URISyntaxException {
+ protected URI getAuthenticatedUrl(String mirrorRepoUrl, String username, String password) throws URISyntaxException {
URI uri = URI.create(mirrorRepoUrl);
String userInfo = username + ":" + password;
@@ -164,46 +170,24 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
@Nonnull Repository repository) {
try {
- int count = 0;
+ boolean ok = true;
logger.debug("MirrorRepositoryHook: validate started.");
- String mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL, "");
- if (mirrorRepoUrl.isEmpty()) {
- count++;
- errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url is required.");
- } else {
- URI uri;
- try {
- uri = URI.create(mirrorRepoUrl);
- if (!uri.getScheme().toLowerCase().startsWith("http") || mirrorRepoUrl.contains("@")) {
- count++;
- errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url must be a valid http(s) " +
- "URI and the user should be specified separately.");
- }
- } catch (Exception ex) {
- count++;
- errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url must be a valid http(s) URI.");
- }
- }
-
- String username = settings.getString(SETTING_USERNAME, "");
- if (username.isEmpty()) {
- count++;
- errors.addFieldError(SETTING_USERNAME, "The username is required.");
- }
+ List mirrorSettings = getMirrorSettings(settings);
- String password = settings.getString(SETTING_PASSWORD, "");
- if (password.isEmpty()) {
- count++;
- errors.addFieldError(SETTING_PASSWORD, "The password is required.");
+ for (MirrorSettings ms : mirrorSettings) {
+ if (!validate(ms, settings, errors)) {
+ ok = false;
+ }
}
// If no errors, run the mirror command
- if (count == 0) {
- encryptPassword(settings, SETTING_PASSWORD, password);
- runMirrorCommand(mirrorRepoUrl, username, password, repository);
+ if (ok) {
+ updateSettings(mirrorSettings, settings);
+ for (MirrorSettings ms : mirrorSettings) {
+ runMirrorCommand(ms, repository);
+ }
}
- logger.debug("MirrorRepositoryHook: validate completed with {} error(s).", count);
} catch (Exception e) {
logger.error("Error running MirrorRepositoryHook validate.", e);
@@ -212,35 +196,80 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
- void encryptPassword(Settings settings, String settingName, String password) {
+ protected List getMirrorSettings(Settings settings) {
+
+ List results = new ArrayList();
+ Map allSettings = settings.asMap();
+ int count = 0;
+
+ for (String key : allSettings.keySet()) {
+ if (key.startsWith(SETTING_MIRROR_REPO_URL)) {
+ String suffix = key.substring(SETTING_MIRROR_REPO_URL.length());
- // Skip if already encrypted
- if (passwordEncryptor.isEncrypted(password)) {
- return;
+ MirrorSettings ms = new MirrorSettings();
+ ms.mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL + suffix, "");
+ ms.username = settings.getString(SETTING_USERNAME + suffix, "");
+ ms.password = settings.getString(SETTING_PASSWORD + suffix, "");
+ ms.suffix = String.valueOf(count++);
+
+ results.add(ms);
+ }
}
- try {
- // Unfortunately the settings are stored in an immutable map, so need to cheat with reflection
- logger.info("Encrypting password");
- Field field = settings.getClass().getDeclaredField("values");
- field.setAccessible(true);
-
- // Create mutable copy of values, and encrypt the password
- @SuppressWarnings("unchecked")
- Map values = (Map) field.get(settings);
- values = new HashMap(values);
- values.put(settingName, passwordEncryptor.encrypt(password));
-
- field.set(settings, values);
-
- } catch (NoSuchFieldException e) {
- throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
- "hook.", e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
- "hook.", e);
+ return results;
+ }
+
+ protected boolean validate(MirrorSettings ms, Settings settings, SettingsValidationErrors errors) {
+
+ boolean result = true;
+
+ if (ms.mirrorRepoUrl.isEmpty()) {
+ result = false;
+ errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix, "The mirror repo url is required.");
+ } else {
+ URI uri;
+ try {
+ uri = URI.create(ms.mirrorRepoUrl);
+ if (!uri.getScheme().toLowerCase().startsWith("http") || ms.mirrorRepoUrl.contains("@")) {
+ result = false;
+ errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix,
+ "The mirror repo url must be a valid http(s) URI and the username " +
+ "should be specified separately.");
+ }
+ } catch (Exception ex) {
+ result = false;
+ errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix,
+ "The mirror repo url must be a valid http(s) URI.");
+ }
+ }
+
+ if (ms.username.isEmpty()) {
+ result = false;
+ errors.addFieldError(SETTING_USERNAME + ms.suffix, "The username is required.");
+ }
+
+ if (ms.password.isEmpty()) {
+ result = false;
+ errors.addFieldError(SETTING_PASSWORD + ms.suffix, "The password is required.");
}
+ return result;
+ }
+
+ protected void updateSettings(List mirrorSettings, Settings settings) {
+
+ Map values = new HashMap();
+
+ // Store each mirror setting
+ for (MirrorSettings ms : mirrorSettings) {
+ values.put(SETTING_MIRROR_REPO_URL + ms.suffix, ms.mirrorRepoUrl);
+ values.put(SETTING_USERNAME + ms.suffix, ms.username);
+ values.put(SETTING_PASSWORD + ms.suffix, passwordEncryptor.encrypt(ms.password));
+ }
+
+ // Unfortunately the settings are stored in an immutable map, so need to cheat with reflection
+ settingsReflectionHelper.set(values, settings);
+
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java b/src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java
index 7b23ef6..4e61575 100644
--- a/src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java
+++ b/src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java
@@ -7,12 +7,35 @@ import com.atlassian.sal.api.pluginsettings.PluginSettings;
*/
public interface PasswordEncryptor {
+ /**
+ * Initialize the password encryptor with the atlassian plugin settings
+ *
+ * @param pluginSettings the plugin settings
+ */
void init(PluginSettings pluginSettings);
+ /**
+ * Checks whether the password is encrypted
+ *
+ * @param password the password to check
+ * @return true if the password is encrypted
+ */
boolean isEncrypted(String password);
+ /**
+ * Encrypts the password if it is not already encrypted
+ *
+ * @param password the password to encrypt
+ * @return encrypted password
+ */
String encrypt(String password);
+ /**
+ * Decrypts the password if it is encrypted
+ *
+ * @param password the encrypted password to decrypt
+ * @return the decrypted password
+ */
String decrypt(String password);
}
diff --git a/src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java b/src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java
new file mode 100644
index 0000000..f7c57c6
--- /dev/null
+++ b/src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java
@@ -0,0 +1,20 @@
+package com.englishtown.stash.hook;
+
+import com.atlassian.stash.setting.Settings;
+
+import java.util.Map;
+
+/**
+ * Helper service to set {@link Settings}
+ */
+public interface SettingsReflectionHelper {
+
+ /**
+ * Set the values field of the {@link Settings} via reflection
+ *
+ * @param values the values to set
+ * @param settings the settings to set the values field on
+ */
+ void set(Map values, Settings settings);
+
+}
diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml
index 5a4e77d..bdddb28 100644
--- a/src/main/resources/atlassian-plugin.xml
+++ b/src/main/resources/atlassian-plugin.xml
@@ -15,6 +15,9 @@
com.englishtown.stash.hook.PasswordEncryptor
+
+ com.englishtown.stash.hook.SettingsReflectionHelper
+
diff --git a/src/main/resources/static/mirror-repository-hook.css b/src/main/resources/static/mirror-repository-hook.css
new file mode 100644
index 0000000..553adaf
--- /dev/null
+++ b/src/main/resources/static/mirror-repository-hook.css
@@ -0,0 +1,3 @@
+.et-remove-button {
+ margin-left: 5px !important;
+}
\ No newline at end of file
diff --git a/src/main/resources/static/mirror-repository-hook.js b/src/main/resources/static/mirror-repository-hook.js
new file mode 100644
index 0000000..8a1126c
--- /dev/null
+++ b/src/main/resources/static/mirror-repository-hook.js
@@ -0,0 +1,41 @@
+define('et/hook/mirror', ['jquery', 'exports'], function ($, exports) {
+
+ exports.init = function (createSubView, createButton) {
+ $('#et-add-button').click(function () {
+ try {
+ var currIndex, index = 0, name, html;
+
+ // Determine the current index from the last password input
+ name = $('div.hook-config-contents input:password').last().attr("name");
+
+ if (name && name.length >= 8) {
+ currIndex = parseInt(name.substring(8));
+ index = (isNaN(currIndex) ? 0 : currIndex) + 1;
+ }
+
+ // Insert template after last field-group div
+ html = createSubView({index: index, config: {}, errors: {}});
+ $('#et-add-button').before(html);
+
+ addRemoveButton();
+
+ } catch (e) {
+ alert(e.message);
+ }
+ });
+
+ function addRemoveButton() {
+ // Select all fieldset groups that don't have a remove button
+ var group = $(".et-mirror-group").not(":has(.et-remove-button)");
+ var html = createButton({name: 'et-remove-button', text: 'Remove', extraClasses: 'et-remove-button'});
+ group.find('.et-mirror-repo input').after(html);
+
+ group.find('.et-remove-button').click(function (e) {
+ $(e.currentTarget).parents('.et-mirror-group').remove();
+ })
+ }
+
+ addRemoveButton();
+ }
+
+});
\ No newline at end of file
diff --git a/src/main/resources/static/mirror-repository-hook.soy b/src/main/resources/static/mirror-repository-hook.soy
index 58a5926..6cf1d39 100644
--- a/src/main/resources/static/mirror-repository-hook.soy
+++ b/src/main/resources/static/mirror-repository-hook.soy
@@ -5,40 +5,77 @@
* @param? errors
*/
{template .view}
- {call aui.form.textField}
- {param id: 'mirrorRepoUrl' /}
- {param value: $config['mirrorRepoUrl'] /}
- {param labelContent}
- {stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.label', 'Mirror Repo URL')}
- {/param}
- {param isRequired: true /}
- {param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.description',
- 'URL to the remote Stash mirrored repo') /}
- {param extraClasses: 'long' /}
- {param errorTexts: $errors ? $errors['mirrorRepoUrl'] : null /}
- {/call}
- {call aui.form.textField}
- {param id: 'username' /}
- {param value: $config['username'] /}
- {param labelContent}
- {stash_i18n('com.englishtown.stash.hook.mirror.strings.username.label', 'Username')}
- {/param}
- {param isRequired: true /}
- {param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.username.description',
- 'The username to use for pushing to the mirror') /}
- {param extraClasses: 'long' /}
- {param errorTexts: $errors ? $errors['username'] : null /}
+
+ // Always add one subview
+ {call .subview data="all"}
+ {param index: 0 /}
{/call}
- {call aui.form.passwordField}
- {param id: 'password' /}
- {param value: $config['password'] /}
- {param labelContent}
- {stash_i18n('com.englishtown.stash.hook.mirror.strings.password.label', 'Password')}
- {/param}
- {param isRequired: true /}
- {param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.password.description',
- 'The password to use for pushing to the mirror') /}
- {param extraClasses: 'long' /}
- {param errorTexts: $errors ? $errors['password'] : null /}
+
+ // Add additional mirrors, up to 10 total
+ {foreach $index in [1, 2, 3, 4, 5, 6, 7, 8, 9]}
+ {if $config['mirrorRepoUrl' + $index] or $config['username' + $index]}
+ {call .subview data="all"}
+ {param index: $index /}
+ {/call}
+ {/if}
+ {/foreach}
+
+ // Button to add additional mirrors
+ {call aui.form.button}
+ {param id: 'et-add-button' /}
+ {param text: 'Add Mirror' /}
{/call}
+
+ // Call init method with subview callback
+
{/template}
+
+/**
+ * @param config
+ * @param? errors
+ * @param index
+ */
+{template .subview}
+
+{/template}
+
+
diff --git a/src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java b/src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java
new file mode 100644
index 0000000..94961aa
--- /dev/null
+++ b/src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java
@@ -0,0 +1,40 @@
+package com.englishtown.stash.hook;
+
+import com.atlassian.stash.internal.setting.MapSettingsBuilder;
+import com.atlassian.stash.setting.Settings;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: adriangonzalez
+ * Date: 5/13/13
+ * Time: 3:54 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class DefaultSettingsReflectionHelperTest {
+
+ @Test
+ public void testSet() throws Exception {
+
+ DefaultSettingsReflectionHelper helper = new DefaultSettingsReflectionHelper();
+ MapSettingsBuilder builder = new MapSettingsBuilder();
+ Map values = new HashMap();
+
+ builder.add("old", "old");
+ values.put("new", "new");
+
+ Settings settings = builder.build();
+ helper.set(values, settings);
+
+ assertNull(settings.getString("old"));
+ assertEquals("new", settings.getString("new"));
+
+ }
+
+}
diff --git a/src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java b/src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java
index f98dc16..1a4bdb6 100644
--- a/src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java
+++ b/src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java
@@ -26,6 +26,8 @@ import org.mockito.runners.MockitoJUnitRunner;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -48,6 +50,8 @@ public class MirrorRepositoryHookTest {
@Mock
private PasswordEncryptor passwordEncryptor;
@Mock
+ private SettingsReflectionHelper settingsReflectionHelper;
+ @Mock
private PluginSettingsFactory pluginSettingsFactory;
@Mock
private PluginSettings pluginSettings;
@@ -79,7 +83,8 @@ public class MirrorRepositoryHookTest {
when(pluginSettingsFactory.createSettingsForKey(anyString())).thenReturn(pluginSettings);
- hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor, pluginSettingsFactory);
+ hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor
+ , settingsReflectionHelper, pluginSettingsFactory);
}
@@ -88,10 +93,14 @@ public class MirrorRepositoryHookTest {
when(passwordEncryptor.decrypt(anyString())).thenReturn(password);
+ Map map = new HashMap();
+ map.put(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL, "");
+
Settings settings = mock(Settings.class);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL))).thenReturn(mirrorRepoUrl);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME))).thenReturn(username);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD))).thenReturn(password);
+ when(settings.asMap()).thenReturn(map);
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq(""))).thenReturn(mirrorRepoUrl);
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq(""))).thenReturn(username);
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq(""))).thenReturn(password);
Repository repo = mock(Repository.class);
when(repo.getName()).thenReturn("test");
@@ -111,8 +120,13 @@ public class MirrorRepositoryHookTest {
GitScm gitScm = mock(GitScm.class);
when(gitScm.getCommandBuilderFactory()).thenThrow(new RuntimeException("Intentional unit test exception"));
- MirrorRepositoryHook hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor, pluginSettingsFactory);
- hook.runMirrorCommand(mirrorRepoUrl, username, password, mock(Repository.class));
+ MirrorRepositoryHook hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor,
+ passwordEncryptor, settingsReflectionHelper, pluginSettingsFactory);
+ MirrorRepositoryHook.MirrorSettings ms = new MirrorRepositoryHook.MirrorSettings();
+ ms.mirrorRepoUrl = mirrorRepoUrl;
+ ms.username = username;
+ ms.password = password;
+ hook.runMirrorCommand(ms, mock(Repository.class));
verify(executor).submit(argumentCaptor.capture());
Callable callable = argumentCaptor.getValue();
@@ -171,18 +185,23 @@ public class MirrorRepositoryHookTest {
Settings settings = mock(Settings.class);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq("")))
+ Map map = new HashMap();
+ map.put(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0", "");
+
+ when(settings.asMap()).thenReturn(map);
+
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), eq("")))
.thenThrow(new RuntimeException("Intentional unit test exception"))
.thenReturn("")
.thenReturn("invalid uri")
.thenReturn("http://should-not:have-user@stash-mirror.englishtown.com/scm/test/test.git")
.thenReturn(mirrorRepoUrl);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq("")))
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), eq("")))
.thenReturn("")
.thenReturn(username);
- when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq("")))
+ when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), eq("")))
.thenReturn("")
.thenReturn(password);
@@ -196,20 +215,20 @@ public class MirrorRepositoryHookTest {
errors = mock(SettingsValidationErrors.class);
hook.validate(settings, errors, repo);
verify(errors, never()).addFormError(anyString());
- verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString());
- verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME), anyString());
- verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD), anyString());
+ verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
+ verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), anyString());
+ verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), anyString());
errors = mock(SettingsValidationErrors.class);
hook.validate(settings, errors, repo);
verify(errors, never()).addFormError(anyString());
- verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString());
+ verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
verify(errors).addFieldError(anyString(), anyString());
errors = mock(SettingsValidationErrors.class);
hook.validate(settings, errors, repo);
verify(errors, never()).addFormError(anyString());
- verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString());
+ verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
verify(errors).addFieldError(anyString(), anyString());
when(passwordEncryptor.isEncrypted(anyString())).thenReturn(true);